Skip to content

Add support for streaming bodies.#2740

Merged
nateberkopec merged 2 commits intopuma:masterfrom
ioquatix:streaming-body
Jan 29, 2022
Merged

Add support for streaming bodies.#2740
nateberkopec merged 2 commits intopuma:masterfrom
ioquatix:streaming-body

Conversation

@ioquatix
Copy link
Copy Markdown
Contributor

@ioquatix ioquatix commented Nov 1, 2021

Proof of concept streaming bodies without using rack.hijack.

@ioquatix
Copy link
Copy Markdown
Contributor Author

ioquatix commented Nov 1, 2021

@nateberkopec if you have some time, do you think you can give me your feedback on making bi-directional streaming a non-optional feature of Rack? It's semantically identical to rack.hijack but without needing to search through the response headers like you currently do to pull out the proc, and instead puts a proc into body.

@nateberkopec
Copy link
Copy Markdown
Member

Looks like there's been some movement on the proposal so we'll need to rebase/update.

@ioquatix
Copy link
Copy Markdown
Contributor Author

Yes sure I will update.

@ioquatix ioquatix force-pushed the streaming-body branch 3 times, most recently from 6b2bba4 to eeba3c3 Compare January 20, 2022 00:11
@MSP-Greg
Copy link
Copy Markdown
Member

MSP-Greg commented Jan 20, 2022

I think the conditional unless body.respond_to?(:each) isn't sufficient. What if the body is a string? Also, I think unless with else is often considered 'odd'?

EDIT: maybe something like:

if !res_info[:response_hijack] && res_body.respond_to?(:call)
  response_hijack = res_body
else
  response_hijack = res_info[:response_hijack]
end

Not sure what I think of additions that make it easy for Puma to have all its threads kept busy?

@nateberkopec nateberkopec added feature waiting-for-changes Waiting on changes from the requestor labels Jan 29, 2022
@nateberkopec
Copy link
Copy Markdown
Member

maybe something like:

@MSP-Greg check the spec, you can't do that. If body responds to each, you have to send each.

@MSP-Greg
Copy link
Copy Markdown
Member

@nateberkopec Good morning. Sorry, I posted the message and later came to the realization that it was totally wrong. Meant to edit/update but having fun with Actions code...

@nateberkopec nateberkopec merged commit a63c0fa into puma:master Jan 29, 2022
@ioquatix ioquatix deleted the streaming-body branch January 29, 2022 21:11
@ioquatix
Copy link
Copy Markdown
Contributor Author

Awesome, thanks for merging this!

JuanitoFatas pushed a commit to JuanitoFatas/puma that referenced this pull request Sep 9, 2022
* Add support for streaming bodies.

* Added a test

Co-authored-by: Nate Berkopec <nate.berkopec@gmail.com>
dentarg added a commit to dentarg/testssl.web that referenced this pull request Oct 28, 2022
Uses "callable body"
- rack/rack#1745
- puma/puma#2740

This doesn't work in Puma 5, it will error like this

    2022-10-28 08:35:53 +0200 Read: #<NoMethodError: undefined method `each' for #<Proc:0x00000001050b2fd8 /Users/dentarg/local_code/testssl.web/app.rb:44 (lambda)>

              res_body.each do |part|
                      ^^^^^>
dentarg added a commit to dentarg/testssl.web that referenced this pull request Oct 28, 2022
Uses "callable body"
- rack/rack#1745
- puma/puma#2740

This doesn't work in Puma 5, it will error like this

    2022-10-28 08:35:53 +0200 Read: #<NoMethodError: undefined method `each' for #<Proc:0x00000001050b2fd8 /Users/dentarg/local_code/testssl.web/app.rb:44 (lambda)>

              res_body.each do |part|
                      ^^^^^>
@dentarg dentarg mentioned this pull request Mar 15, 2023
@MSP-Greg
Copy link
Copy Markdown
Member

MSP-Greg commented Sep 2, 2024

@ioquatix

Good day. This PR's test used HTTP/1.0. But, when most people here the term 'streaming', it implies more than one body segment.

The old HTTP/1.0 spec seems to state that 'content-length' must always be specified. Kind of a conflict here.

Was there a reason you used HTTTP/1.0 instead of HTTTP/1.1?

@MSP-Greg
Copy link
Copy Markdown
Member

MSP-Greg commented Sep 2, 2024

@dentarg

Sorry for the Sinatra question. IIRC, there were some changes to Puma related to Sinatra and 'streaming'. Can't recall. WIll Sinatra send a 'streaming' response (or an Enum body) to an HTTP/1.0 client? If so, that kind of conflicts with the HTTP/1.0 spec, which states that the content length must always be specified, since HTTP/1.0 doesn't support chunked.

And, yes, this is a pita, since I doubt there's much HTTP/1.0 use anymore...

@ioquatix
Copy link
Copy Markdown
Contributor Author

ioquatix commented Sep 3, 2024

Sinatra send a 'streaming' response (or an Enum body) to an HTTP/1.0 client? If so, that kind of conflicts with the HTTP/1.0 spec, which states that the content length must always be specified, since HTTP/1.0 doesn't support chunked.

You can use connection: close and then you don't need to send a content length. That's the correct way to do streaming with HTTP/1.0 connections.

@MSP-Greg
Copy link
Copy Markdown
Member

MSP-Greg commented Sep 3, 2024

@ioquatix

Thanks for the response. I'll see what curl does tomorrow...

@ioquatix
Copy link
Copy Markdown
Contributor Author

ioquatix commented Sep 3, 2024

@MSP-Greg let me know how it goes. Don't forget to use --no-buffer.

@dentarg
Copy link
Copy Markdown
Member

dentarg commented Sep 3, 2024

@MSP-Greg to my knowledge Sinatra does not take the HTTP version into account for anything (but feel free to double check me)

also: sinatra/sinatra#1892

@MSP-Greg
Copy link
Copy Markdown
Member

MSP-Greg commented Sep 3, 2024

@ioquatix

This recent problem came about when revising the Puma test suite. I don't recall the last time I looked at HTTP/1.0, and I was busy with some other family things.

I believe you're correct. I incorrectly read the 'spec' (https://www.w3.org/Protocols/HTTP/1.0/spec.html). Sorry.

I found the following in section 7.2.2:

When an Entity-Body is included with a message, the length of that body may be determined in one of two ways. If a Content-Length header field is present, its value in bytes represents the length of the Entity-Body. Otherwise, the body length is determined by the closing of the connection by the server.

The next paragraph essentially explains why that won't work for a request, so 'content-length' must be specified for request bodies, which is also mentioned here, with the phrase:

A valid Content-Length field value is required on all HTTP/1.0 request messages containing an entity body.

@ioquatix
Copy link
Copy Markdown
Contributor Author

ioquatix commented Sep 3, 2024

In theory, it's possible to shutdown(WR) which allows bi-directional streaming in HTTP/1.0 but better just to use HTTP/1.1 with chunked encoding. If you try it even with Puma, I'm pretty sure it would just work (or perhaps only require very minimal changes), due to the semantics of how sockets work. It's not a bad idea to support this model even if it's technically outside the spec...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature waiting-for-changes Waiting on changes from the requestor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants