we already have res.statusCode=
I haven't had issues with .headers being an object, it's easy to check in a method if the field value is an array or not. On Feb 8, 6:59 pm, Dean Landolt <d...@deanlandolt.com> wrote: > On Wed, Feb 8, 2012 at 6:07 PM, Isaac Schlueter <i...@izs.me> wrote: > > I think I agree with pretty much all of this, Mikeal. Exposing ctors > > really invites the wrong kind of composability, but we need to make > > the core systems nicer in the ways you describe. The response header > > handling really needs to be cleaned up. It mostly works, but has some > > odd edges where it doesn't. > > > Constraints: > > 1. We must maintain backwards compatibility unless it is completely > > unreasonable to do so. This can often be done by re-implementing old > > API surfaces in terms of new ones, but please bear this in mind for > > any change. > > 2. API cleanup should generally not introduce new features, but merely > > make existing features more intuitive, organized, and consistent. > > 3. Performance regressions cannot be tolerated. Express or request or > > fstream can do a bunch of extra junk to make a cuter API, and give up > > some performance in doing so, but node-core must be as fast as > > possible. > > > Here's a half-thought-out proposal. Please shoot it down in > > constructive ways. :) > > > Expose the actual headers as they will be written. This must be a 2d > > array. An object is not the right data structure, because there can > > be multiple values for the same key, and though it shouldn't, order > > does matter in some very rare edge cases. Like module.exports, if > > this value is overwritten, or manually modified, then that's the > > "real" header. > > > response.headers = [ [key, value], ... ] > > If you're going this low level why bother with nested arrays? Why not [ > key, value, key, value ... ]? There's no difference and presumably you'll > be using helpers to manipulate anyway. > > > Sugar around response.headers.push([key, value]), but giving us a > > place to add intelligent defaults, validation, etc. We should push > > this api everywhere as the default: > > > response.setHeader("key", "value") // Set a header, adding a second > > one if there's already one by that name. > > response.setHeader("key", "value", true) // Overwrite any existing > > header by that name. > > Why not separate setHeader and addHeader methods? This should make usage > more obvious. Magic bools like this only serve to confuse. > > > Set the status as a property: > > response.status = 200; // should this just default to 200? > > LGTM. What about the status message text? > > > > > > > > > > > Backwards-compatible shim method: > > response.writeHead = function (status, headers) { > > this.status = status; > > if (Array.isArray(headers)) { > > this.headers = headers; > > } else { > > Object.keys(headers).forEach(function (k) { > > this.setHeader(k, headers[k]); > > }); > > } > > }; > > > Don't send the actual header on the socket until the first .write() or > > .end(). At that time, response.headerSent = true, and any calls to > > response.setHeader() trigger an error event. > > What about any direct manipulation of response.headers? Same thing? > > > > > > > > > > > On Wed, Feb 8, 2012 at 13:39, tjholowaychuk <tjholoway...@gmail.com> > > wrote: > > > Yeah, unless you're one of us writing these higher-level things you > > > probably wont even really be concerned about how node does things, > > > since if you're just using straight-up node you're probably happy with > > > writeHead() etc. It's awesome having a low-level core that is not > > > overly opinionated about this sort of thing but at the same time we > > > almost need that, otherwise the community just becomes a diverged > > > mess. > > > > It's probably not worth talking about rack-like stuff since that'll > > > never be in core, but I guess the key thing is that we shouldn't need > > > something like that to build pluggable things. Say instead of manually > > > checking accept-encoding all over you want: > > > > http.createServer(function(req, res){ > > > acceptEncoding(req, res); > > > // go on with regular stuff here > > > }); > > > > IMHO we should at least supply something reasonable to make that > > > happen. In Connect I'm using a "header" event, it's not as "clean" as > > > something like rack but like I've said before I really dont want to > > > diverge from what core gives us otherwise it renders that stuff > > > useless to other people (like it does now) and splits the community > > > more than it should > > > > On Feb 8, 1:35 pm, Mikeal Rogers <mikeal.rog...@gmail.com> wrote: > > >> Yup, none of this is new. > > > >> I think that we need to reach a consensus that this is our goal. I know > > that in core there is a tendency to hold internal state and refrain from > > exposure. I think that some people believe it is "safer" or more "secure" > > and you can see this show a little in the thread about exposing core > > constructors. > > > >> A pre-requisite to me writing patches that solve this is a cultural > > consensus that we are working towards a composable core, and while I know > > TJ is all for it :) I don't think this goal is currently shared across the > > core community and the practice to date seems to lead towards writing > > things initially very restrictive initially and then people like TJ and > > Marco fighting to expose them. > > > >> On Feb 8, 2012, at February 8, 20124:18 PM, tjholowaychuk wrote: > > > >> > +1 been saying this for years > > > >> > On Feb 8, 1:04 pm, Mikeal Rogers <mikeal.rog...@gmail.com> wrote: > > >> >> All the streams in core are in some half state between declarative > > and composable. > > > >> >> http.ServerResponse is probably the biggest/worst example where: > > > >> >> http.writeHead(status, headers) > > > >> >> can, in some cases, entirely opt out of the composable headers set: > > > >> >> http.setHeader(name, value) > > > >> >> in particular, this happens when you pass an array of tuples as the > > headers argument to writeHead. > > > >> >> Then there is http.ClientRequest, which is not composable at all and > > has no setHeader() method. > > > >> >> I have a similar problem with every stream in core except sockets. > > All of the streams in core take, at some point, a set of parameters that > > set a bunch of internal state and *start* an IO operation. Until that IO > > operation hits a particular event, in the future, none of that internal > > state is actually used. Some of that state can be mutated (is composable), > > some currently isn't (is not composable), and some of it is mutable if you > > access internal properties (ewwww). > > > >> >> If the goal of core is to reach API stability we need to get core to > > a place where it's extensible. There is a similar thread to this effect > > about exposing core constructors, but I'd like to stay on track in this > > thread and just talk about composability because it doesn't have many of > > the same concerns people have about exposing core constructors. > > > >> >> *Most* of the objects in core are accessed by userland as the > > subject of an event. When those objects are not composable we incredibly > > limit the extensibility of core, even when we expose the constructors, and > > it leads to the worst kind of monkey patching. There are even cases where > > core objects that get exposed by libraries have certain methods entirely > > removed because they break composability (I know TJ was considering > > removing writeHead when exposed by Express). > > > >> >> A few things would need to happen to make core more composable. > > > >> >> 1) Internal state needs to become external state. > > >> >> and > > >> >> 2) The removal, or "re-integration", of methods that currently break > > composability. > > > >> >> We may also need to add more events to some objects. Some good > > examples, which have been added, are the 'open' and 'socket' methods on > > fs.ReadStream/fs.WriteStream and http.ServerResponse. > > > >> >> Anywhere we can expose internal state publicly we increase > > composability because we allow new mutations that depend on that state the > > way internal logic depends on it. As we do this we'll also realize more > > places where we break that mutability. > > > >> >> Thoughts?