* rational for rewind() @ 2014-05-22 21:12 Torsten Robitzki 2014-05-23 10:46 ` Magnus Holm 2014-07-17 22:34 ` Eric Wong 0 siblings, 2 replies; 11+ messages in thread From: Torsten Robitzki @ 2014-05-22 21:12 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 1207 bytes --] Hello, I'm implementing a C++ comet web server, that (tries) to implement rack to adapt ruby applications. Currently I'm reading a body very naively put the body into a ruby String and wrap it with a StringIO to provide the rack.input for the implementation. As I'm going to use the server for uploading images, I would like to implement a real, stream-like object to circumvent the need to buffer the POST body before handing it to the application. Now, I've read the rack specs and read about rewind(). To implement rewind(), I would have to store the whole body, even when the upstream application just calculates some kind of checksum on the body, or uploads it to s3. What's the rational behind this part of the specification? Is it possible to not implement rewind() and to tell applications that need rewind(), to keep there own copy of the body, in case it is needed? kind regards, Torsten -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 1476 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-05-22 21:12 rational for rewind() Torsten Robitzki @ 2014-05-23 10:46 ` Magnus Holm 2014-05-24 12:35 ` Torsten Robitzki 2014-07-17 22:34 ` Eric Wong 1 sibling, 1 reply; 11+ messages in thread From: Magnus Holm @ 2014-05-23 10:46 UTC (permalink / raw) To: rack-devel On Thu, May 22, 2014 at 11:12 PM, Torsten Robitzki <Torsten@robitzki.de> wrote: > Hello, > I'm implementing a C++ comet web server, that (tries) to implement rack to > adapt ruby applications. Currently I'm reading a body very naively put the > body into a ruby String and wrap it with a StringIO to provide the > rack.input for the implementation. As I'm going to use the server for > uploading images, I would like to implement a real, stream-like object to > circumvent the need to buffer the POST body before handing it to the > application. > > Now, I've read the rack specs and read about rewind(). To implement > rewind(), I would have to store the whole body, even when the upstream > application just calculates some kind of checksum on the body, or uploads it > to s3. What's the rational behind this part of the specification? Is it > possible to not implement rewind() and to tell applications that need > rewind(), to keep there own copy of the body, in case it is needed? > > kind regards, > Torsten One word: Middleware. Some middleware need to access the HTTP body (e.g. for fetching the CSRF-token from a POST-parameter). In order to allow middleware to process HTTP bodies, rewind() was added. Yes, we are all aware of the issues it present. Yes, it sucks. Yes, you can implement a server which doesn't support rewind(), but it won't work with many middleware. // Magnus Holm -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-05-23 10:46 ` Magnus Holm @ 2014-05-24 12:35 ` Torsten Robitzki 2014-06-30 22:16 ` Daniel Doubrovkine 0 siblings, 1 reply; 11+ messages in thread From: Torsten Robitzki @ 2014-05-24 12:35 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 1006 bytes --] Hi Magnus, > One word: Middleware. > sorry, I didn't found the old discussions here regarding rewind (maybe a typo in my search phrase). Is there any proposal planned to change the specs to allow a more effective input implementation? My first thought was something like an unrewindable_input() function, that provides an input stream that doesn't provide a rewind() interface, but buffers the data read through this interface, so that the original input can still provide this data. If all middleware would be aware of this interface and the final application wouldn't need to rewind(), the input would just have to store the part of the input that have to be processed twice. Cheers, Torsten -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 1444 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-05-24 12:35 ` Torsten Robitzki @ 2014-06-30 22:16 ` Daniel Doubrovkine 2014-07-15 4:30 ` James Tucker 0 siblings, 1 reply; 11+ messages in thread From: Daniel Doubrovkine @ 2014-06-30 22:16 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 2004 bytes --] If you're interested in an example that uses rewind, check out https://github.com/intridea/grape/blob/5c785324a071f7eb527683256ad34db70e965830/lib/grape/middleware/formatter.rb#L55 . Basically, in Rails the input would get read, and left at the end of the stream. So when Grape was mounted on Rails it would want to re-read that input to get more/better/different data and therefore you had to call rewind. On Sat, May 24, 2014 at 8:35 AM, Torsten Robitzki <Torsten@robitzki.de> wrote: > Hi Magnus, > > >> One word: Middleware. >> > > sorry, I didn't found the old discussions here regarding rewind (maybe a > typo in my search phrase). Is there any proposal planned to change the > specs to allow a more effective input implementation? > > My first thought was something like an unrewindable_input() function, that > provides an input stream that doesn't provide a rewind() interface, but > buffers the data read through this interface, so that the original input > can still provide this data. If all middleware would be aware of this > interface and the final application wouldn't need to rewind(), the input > would just have to store the part of the input that have to be processed > twice. > > Cheers, > Torsten > > -- > > --- > You received this message because you are subscribed to the Google Groups > "Rack Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to rack-devel+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- dB. | Moscow - Geneva - Seattle - New York code.dblock.org - @dblockdotorg <http://twitter.com/#!/dblockdotorg> - artsy.net - github/dblock <https://github.com/dblock> -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 3631 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-06-30 22:16 ` Daniel Doubrovkine @ 2014-07-15 4:30 ` James Tucker 0 siblings, 0 replies; 11+ messages in thread From: James Tucker @ 2014-07-15 4:30 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 2727 bytes --] The use case is generally explained in previous mails, but yes it's a problem for these kinds of servers. My best recommendation to you is that you violate the recommendation and clearly document the rationale. We can't easily address this in the SPEC at this time. On Mon, Jun 30, 2014 at 3:16 PM, Daniel Doubrovkine <dblock@dblock.org> wrote: > If you're interested in an example that uses rewind, check out > https://github.com/intridea/grape/blob/5c785324a071f7eb527683256ad34db70e965830/lib/grape/middleware/formatter.rb#L55 > . > > Basically, in Rails the input would get read, and left at the end of the > stream. So when Grape was mounted on Rails it would want to re-read that > input to get more/better/different data and therefore you had to call > rewind. > > > On Sat, May 24, 2014 at 8:35 AM, Torsten Robitzki <Torsten@robitzki.de> > wrote: > >> Hi Magnus, >> >> >>> One word: Middleware. >>> >> >> sorry, I didn't found the old discussions here regarding rewind (maybe a >> typo in my search phrase). Is there any proposal planned to change the >> specs to allow a more effective input implementation? >> >> My first thought was something like an unrewindable_input() function, >> that provides an input stream that doesn't provide a rewind() interface, >> but buffers the data read through this interface, so that the original >> input can still provide this data. If all middleware would be aware of this >> interface and the final application wouldn't need to rewind(), the input >> would just have to store the part of the input that have to be processed >> twice. >> >> Cheers, >> Torsten >> >> -- >> >> --- >> You received this message because you are subscribed to the Google Groups >> "Rack Development" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to rack-devel+unsubscribe@googlegroups.com. >> For more options, visit https://groups.google.com/d/optout. >> > > > > -- > > dB. | Moscow - Geneva - Seattle - New York > code.dblock.org - @dblockdotorg <http://twitter.com/#!/dblockdotorg> - > artsy.net - github/dblock <https://github.com/dblock> > > -- > > --- > You received this message because you are subscribed to the Google Groups > "Rack Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to rack-devel+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 4961 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-05-22 21:12 rational for rewind() Torsten Robitzki 2014-05-23 10:46 ` Magnus Holm @ 2014-07-17 22:34 ` Eric Wong 2014-07-17 23:10 ` James Tucker 1 sibling, 1 reply; 11+ messages in thread From: Eric Wong @ 2014-07-17 22:34 UTC (permalink / raw) To: rack-devel (resending my original message for the archives, original seems lost, Torsten already got this privately) Torsten Robitzki <Torsten@Robitzki.de> wrote: > Hello, > I'm implementing a C++ comet web server, that (tries) to implement rack to > adapt ruby applications. Currently I'm reading a body very naively put the > body into a ruby String and wrap it with a StringIO to provide the > rack.input for the implementation. As I'm going to use the server for > uploading images, I would like to implement a real, stream-like object to > circumvent the need to buffer the POST body before handing it to the > application. unicorn implements input like tee(1) doing lazy, rewindable buffering: http://unicorn.bogomips.org/Unicorn/TeeInput.html > Now, I've read the rack specs and read about rewind(). To implement > rewind(), I would have to store the whole body, even when the upstream > application just calculates some kind of checksum on the body, or uploads > it to s3. What's the rational behind this part of the specification? Is it > possible to not implement rewind() and to tell applications that need > rewind(), to keep there own copy of the body, in case it is needed? I don't know the rationale, but I suspect it's to make life easier for application/API authors to know the data will exist for the lifetime of the request/response cycle. But I think having rewind as part of the spec sucks. I seem to recall there was hope of getting rid of it for Rack 2 (if it ever happens). However, since I'm not sure if Rack 2 will happen, rewind can already be disabled and break spec in servers I implement: unicorn has a "rewindable_input <true|false>" option (default=true): http://unicorn.bogomips.org/Unicorn/Configurator.html yahns is a tri-state: "input_buffering <:lazy|true|false>" option: http://yahns.yhbt.net/yahns_config.txt (default=true) Fwiw, rewindable_input(true) in unicorn is equivalent to input_buffering(:lazy) in yahns. This is because unicorn expects nginx to buffer for slow clients, whereas yahns does not require nginx and buffers asynchronously even with trickling clients. -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-07-17 22:34 ` Eric Wong @ 2014-07-17 23:10 ` James Tucker 2014-07-17 23:44 ` Eric Wong 2014-07-19 9:55 ` Torsten Robitzki 0 siblings, 2 replies; 11+ messages in thread From: James Tucker @ 2014-07-17 23:10 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 3704 bytes --] On Thu, Jul 17, 2014 at 3:34 PM, Eric Wong <e@80x24.org> wrote: > (resending my original message for the archives, original seems lost, > Torsten already got this privately) > > Torsten Robitzki <Torsten@Robitzki.de> wrote: > > Hello, > > I'm implementing a C++ comet web server, that (tries) to implement rack > to > > adapt ruby applications. Currently I'm reading a body very naively put > the > > body into a ruby String and wrap it with a StringIO to provide the > > rack.input for the implementation. As I'm going to use the server for > > uploading images, I would like to implement a real, stream-like object to > > circumvent the need to buffer the POST body before handing it to the > > application. > > unicorn implements input like tee(1) doing lazy, rewindable buffering: > http://unicorn.bogomips.org/Unicorn/TeeInput.html This is the approach I would take. I'm not sure if TeeInput supports it, but for a generic server supporting websocket type use cases, I'd add a discardable buffer API too, so you can "hijack" the input stream and release any stale resources. > Now, I've read the rack specs and read about rewind(). To implement > > rewind(), I would have to store the whole body, even when the upstream > > application just calculates some kind of checksum on the body, or uploads > > it to s3. What's the rational behind this part of the specification? Is > it > > possible to not implement rewind() and to tell applications that need > > rewind(), to keep there own copy of the body, in case it is needed? > > I don't know the rationale, but I suspect it's to make life easier for > application/API authors to know the data will exist for the lifetime > of the request/response cycle. > > But I think having rewind as part of the spec sucks. Agreed. I generally think a lot of concerns that used to be in middleware should not be so (e.g. chunking and content-length), but this concern actually could be handled by middleware so apps that want it can add it in the appropriate place in the chain. This would remove the responsibility from the server authors, which opens up a lot of potential optimizations and flexibility. We also lack a lot of potentially useful security considerations in this area (i.e. both static and dynamic configurable limits). > I seem to recall > there was hope of getting rid of it for Rack 2 (if it ever happens). > Yup. > However, since I'm not sure if Rack 2 will happen, rewind can already > be disabled and break spec in servers I implement: > > unicorn has a "rewindable_input <true|false>" option (default=true): > http://unicorn.bogomips.org/Unicorn/Configurator.html > > yahns is a tri-state: "input_buffering <:lazy|true|false>" option: > http://yahns.yhbt.net/yahns_config.txt (default=true) > > Fwiw, rewindable_input(true) in unicorn is equivalent to > input_buffering(:lazy) in yahns. This is because unicorn expects nginx > to buffer for slow clients, whereas yahns does not require nginx and > buffers asynchronously even with trickling clients. > This is the approach I recommend today. > > -- > > --- > You received this message because you are subscribed to the Google Groups > "Rack Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to rack-devel+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 5522 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-07-17 23:10 ` James Tucker @ 2014-07-17 23:44 ` Eric Wong 2014-07-18 0:00 ` James Tucker 2014-07-19 9:55 ` Torsten Robitzki 1 sibling, 1 reply; 11+ messages in thread From: Eric Wong @ 2014-07-17 23:44 UTC (permalink / raw) To: rack-devel James Tucker <jftucker@gmail.com> wrote: > > Torsten Robitzki <Torsten@Robitzki.de> wrote: > > > Hello, > > > I'm implementing a C++ comet web server, that (tries) to implement rack > > to > > > adapt ruby applications. Currently I'm reading a body very naively put > > the > > > body into a ruby String and wrap it with a StringIO to provide the > > > rack.input for the implementation. As I'm going to use the server for > > > uploading images, I would like to implement a real, stream-like object to > > > circumvent the need to buffer the POST body before handing it to the > > > application. > > > > unicorn implements input like tee(1) doing lazy, rewindable buffering: > > http://unicorn.bogomips.org/Unicorn/TeeInput.html > > > This is the approach I would take. I'm not sure if TeeInput supports it, > but for a generic server supporting websocket type use cases, I'd add a > discardable buffer API too, so you can "hijack" the input stream and > release any stale resources. I'm not completely sure what you mean[1], but both yahns and unicorn support rack.hijack. TeeInput cannot read beyond the current HTTP request boundary, so I'm not sure there's anything that needs to change in the HTTP servers. If a client pipelines non-HTTP data after a normal HTTP request, that would be a problem; but pipelining during a protocol change/negotiation seems wrong to begin with. [1] I've not tried rack.hijack with websockets, yet I just (hopefully) implemented it according to the Rack spec. GUI-oriented websocket things just do not interest me. -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-07-17 23:44 ` Eric Wong @ 2014-07-18 0:00 ` James Tucker 2014-07-18 0:43 ` Eric Wong 0 siblings, 1 reply; 11+ messages in thread From: James Tucker @ 2014-07-18 0:00 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 3064 bytes --] On Thu, Jul 17, 2014 at 4:44 PM, Eric Wong <e@80x24.org> wrote: > James Tucker <jftucker@gmail.com> wrote: > > > Torsten Robitzki <Torsten@Robitzki.de> wrote: > > > > Hello, > > > > I'm implementing a C++ comet web server, that (tries) to implement > rack > > > to > > > > adapt ruby applications. Currently I'm reading a body very naively > put > > > the > > > > body into a ruby String and wrap it with a StringIO to provide the > > > > rack.input for the implementation. As I'm going to use the server for > > > > uploading images, I would like to implement a real, stream-like > object to > > > > circumvent the need to buffer the POST body before handing it to the > > > > application. > > > > > > unicorn implements input like tee(1) doing lazy, rewindable buffering: > > > http://unicorn.bogomips.org/Unicorn/TeeInput.html > > > > > > This is the approach I would take. I'm not sure if TeeInput supports it, > > but for a generic server supporting websocket type use cases, I'd add a > > discardable buffer API too, so you can "hijack" the input stream and > > release any stale resources. > > I'm not completely sure what you mean[1], but both yahns and unicorn > support rack.hijack. TeeInput cannot read beyond the current HTTP > request boundary, so I'm not sure there's anything that needs to change > in the HTTP servers. > Right, I just mean "I own the socket now, throw away any buffers" If a client pipelines non-HTTP data after a normal HTTP request, that > would be a problem; but pipelining during a protocol change/negotiation > seems wrong to begin with. > Yep, pipelining and upgrades with close semantics are evil. The correct approach is to just discard any in-flight pipelined requests, and technically they should have no side-effects due to the idempotence rule. This is the important reason to strongly recommend using non-idempotent HTTP methods for upgrade routes, as correct pipeline implementations should serialize around those. All that said though, it's generally even more wise to handle/split routing for these kinds of things at the load balancer level, as they have totally different load semantics. > > > [1] I've not tried rack.hijack with websockets, yet > I just (hopefully) implemented it according to the Rack spec. > GUI-oriented websocket things just do not interest me. > Totally fair :-) I use SSE a lot more than websockets myself, as it's less complicated across the whole stack. > > -- > > --- > You received this message because you are subscribed to the Google Groups > "Rack Development" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to rack-devel+unsubscribe@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 4668 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-07-18 0:00 ` James Tucker @ 2014-07-18 0:43 ` Eric Wong 0 siblings, 0 replies; 11+ messages in thread From: Eric Wong @ 2014-07-18 0:43 UTC (permalink / raw) To: rack-devel James Tucker <jftucker@gmail.com> wrote: > Right, I just mean "I own the socket now, throw away any buffers" OK, so probably something like the following to remove references to the HTTP parser and input object: http://yhbt.net/yahns-public/m/20140718003320.GA14749@dcvr.yhbt.net.html The Rack app is still expected to cleanup env itself. -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: rational for rewind() 2014-07-17 23:10 ` James Tucker 2014-07-17 23:44 ` Eric Wong @ 2014-07-19 9:55 ` Torsten Robitzki 1 sibling, 0 replies; 11+ messages in thread From: Torsten Robitzki @ 2014-07-19 9:55 UTC (permalink / raw) To: rack-devel [-- Attachment #1: Type: text/plain, Size: 1696 bytes --] Hello, Am Freitag, 18. Juli 2014 01:10:03 UTC+2 schrieb raggi: > Agreed. I generally think a lot of concerns that used to be in middleware > should not be so (e.g. chunking and content-length), but this concern > actually could be handled by middleware so apps that want it can add it in > the appropriate place in the chain. This would remove the responsibility > from the server authors, which opens up a lot of potential optimizations > and flexibility. We also lack a lot of potentially useful security > considerations in this area (i.e. both static and dynamic configurable > limits). > depending on how much middlewares need this feature, it might be more effective to implement the buffering in the server as this is the part of the stack that is nearest to the metal. Maybe we could propose an API for middle wares that need rewinding and then do a reference implementation that could be implemented naively in ruby and added onto of all existing server implementations. I think such an API needs to address: - that in case that no middleware needs to rewind, the input needs not to be buffered - in case the middlewares just need to peek into the beginning of the input, only that beginning of the stream have to be buffered. - it should as backward compatible as possible. At least no middleware that does not use rewind() should see a difference. regards, Torsten -- --- You received this message because you are subscribed to the Google Groups "Rack Development" group. To unsubscribe from this group and stop receiving emails from it, send an email to rack-devel+unsubscribe@googlegroups.com. For more options, visit https://groups.google.com/d/optout. [-- Attachment #2: Type: text/html, Size: 2213 bytes --] ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2014-07-19 9:55 UTC | newest] Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-05-22 21:12 rational for rewind() Torsten Robitzki 2014-05-23 10:46 ` Magnus Holm 2014-05-24 12:35 ` Torsten Robitzki 2014-06-30 22:16 ` Daniel Doubrovkine 2014-07-15 4:30 ` James Tucker 2014-07-17 22:34 ` Eric Wong 2014-07-17 23:10 ` James Tucker 2014-07-17 23:44 ` Eric Wong 2014-07-18 0:00 ` James Tucker 2014-07-18 0:43 ` Eric Wong 2014-07-19 9:55 ` Torsten Robitzki
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).