pleroma.debian.social

pleroma.debian.social

Hey, friends. Is there a sensible way to make a script return an HTTP header before it has finished processing?

```
<?php
header( "Location: https://example.com/" );
sleep(100);
die();
```

By sensible, I mean "doesn't spawn an `exec` process or rely on an external script to finish the job."

@Edent Output something. *maybe* calling flush() would do it

@Edent I don't know PHP but is there a 'flush' call available? I used to do this in Java servlets to get stuff on the wire ASAP for a partial page display while the server chewed stuff over. It required a gzip compressor that would honour a partial flush also.

@derickr @Edent flush() would be my bet too

@Phil_Tanner @derickr
Sadly not. Have added both echo and flush. Still doesn't return anything before the sleep ends.

@Edent @Phil_Tanner @derickr Server may be buffering. Try adding a few KB of whitespace and see what happens?

@Edent check the 204 status code

@RollingDice but I want a redirect.

@slightlyoff @Phil_Tanner @derickr
Aha! That seems to work. Thanks 🙂

@Edent what php version are you on? It looks like it was fixed just a few years ago

https://github.com/php/php-src/issues/12385

@gundersen 8.5 - but on Apache.

@Edent Your example doesn't work outside of the box? I *think* this would've worked the last time I used PHP? Could it be that the problem is rather on the browser side and that it's waiting for the </head> closure?

@highvoltage there's no <head> sent. It is a HTTP 302 redirect.

@Edent and if you pass your URL to curl -i -s, what do you get?

@highvoltage
The
< HTTP/2 302
< location: https://example.com/

Isn't sent until 10 seconds have passed.

@Edent Ah I understand better what's happening now, but don't have a solution, sorry :)
replies
0
announces
0
likes
0

OK, the problem is now with 's Requests.

It see the HTTP 302, but doesn't follow it until the connection is terminated. There's no obvious way to tell requests "Follow the redirect header as soon as you see it and ignore the body."

@Edent Well for that you'll need to sent Content-Length: 0 or something because otherwise the request is only complete when the connection is closed?

@tomh
That doesn't seem to work either. And the 302 redirect is implicitly zero length, I think?

@Edent Where i've had to do similar in the past, I've tended to include a `Connection: close` along with a `content-length: 0` (it'd be before your flush())

<?php
header("Location: example.com");
header("Connection: close");
header("Content-length: 0");
flush();
sleep(100);
do_thing();
die();

But, that was a long time ago, so it might be that Curl has changed in the meantime

@Edent I'd have thought a 302 redirect body was so short you could hardly tell if you were waiting for it to finish. Is something causing a delay, or do I just misunderstand?

@ndw as above - the server is still processing some information, so doesn't explicitly close the connection.

@Edent A 302 doesnt have a body. I assume the problem really is on another layer: your server will not consider the request finished until the PHP finishes, and thus not send the CRLF CRLF to end the response header (and thus the response). What you're looking for is a way for the server to execute the PHP in the background. Not sure that exists.

@henryk
The server *is* executing in the background - it successfully sends the redirect which curl immediately follows. Then it waits 10 seconds. Then writes a file to disk.

That all works.

What isn't working is that Python's Requests isn't following the 302 as soon as it is seen.

@Edent Check the HTTP versions and maybe use tcpdump to confirm byte level behavior. A client cannot (and should not) follow a redirect until the header is ended (by CRLF CRLF). After the header has ended, there's no body, and thus shouldn't even be a way for Python to wait for anything else.

EXCEPT: Connection close in HTTP 1.0 (vs. keepalive in 1.1).

@henryk so the wrinkle is, I *am* sending a body because it's the only way to get PHP to send the header.

I can see the header come through just fine. I'll try adding in a manual \r\n to see if that convinces Requests that the connection is complete.

@Edent Ugh, sorry. I took a nap and apparently wasn't fully awake yet. Yeah, 302 can have a body, of course. And it may be that requests wants to read it in full before returning the response object. Only way to check that is in the requests code.

@Edent It looks like requests will happily stream a 200 response but will buffer the exact same response with a 302.

@jleedev oooh! Interesting.
Would you mind adding that to https://github.com/psf/requests/issues/7248 ?

@Edent TBH this sounds like you need a work queue, but setting one up is maybe too much for you small need.

@Edent I wonder if Caddy could be taught to intercept redirect responses from a backend after the headers and before the body…