serving GAE applications over http - java

I have implemented an application on GAE which can be accessible through https://<my_app_id>.appspot.com. Now I have a custom domain registered with Register.com. As described in GAE documentation I have mapped my custom domain to https://<my_app_id>.appspot.com and I see my application getting served from my custom domain. But I see requests are failed with error "SSL required to perform this operation". But I don't have any SSL certificate. And Can I serve my application without SSL? I mean just using http
UPDATED:
Response on executing url curl -v example.org/_ah/api/myapi/v1/package/ -o /dev/null
* Adding handle: conn: 0x1fa7e80
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x1fa7e80) send_pipe: 1, recv_pipe: 0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* About to connect() to mydomain.com port 80 (#0)
* Trying ipaddress...
* Connected to mydomain.com (ipaddress) port 80 (#0)
> GET /_ah/api/myapp/v1/package/ HTTP/1.1
> User-Agent: curl/7.30.0
> Host: mydomain.com
> Accept: */*
>
< HTTP/1.1 404 Not Found
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: Fri, 01 Jan 1990 00:00:00 GMT
< Date: Tue, 23 Jun 2015 12:26:50 GMT
< Vary: X-Origin
< Content-Type: text/html; charset=UTF-8
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
* Server GSE is not blacklisted
< Server: GSE
< Alternate-Protocol: 80:quic,p=0
< Accept-Ranges: none
< Vary: Origin,Accept-Encoding
< Transfer-Encoding: chunked
<
{ [data not shown]
Warning: Failed to create the file /dev/null: No such file or directory
* Failed writing body (0 != 9)
* Failed writing data
0 0 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0
* Closing connection 0
curl: (23) Failed writing body (0 != 9)

There two things you've missed from docs:
Google Cloud Endpoints requires SSL. If you need to access your backend API in a system not supporting SSL, you'll need to either update the system to support SSL or use a proxy.
and
Google Cloud Endpoints does not support custom domains.
See https://cloud.google.com/appengine/docs/java/endpoints/

Related

Web request works in browser, but it gives 'HTTP 403' in Java

I am running a Java program to download data from a Stock API. The URL is
https://tvc4.investing.com/49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918
If I run this URL from the browser, I get a JSON as a response. However, if I run it from a Java program I get a 403 forbidden. I looked up the Developer tools in Chrome and set up all the HTTP request headers in the Java program. I added User-Agent/Cookie, etc. However, I still get the Forbidden 403 error.
Below are the HTTP Headers that I have set:
Below is the stack trace that I get in my Java program.
java.io.IOException: Server returned HTTP response code: 403 for URL: https://tvc4.investing.com/49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1997)
at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1589)
at java.base/java.net.URLConnection.getContent(URLConnection.java:753)
at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getContent(HttpsURLConnectionImpl.java:404)
at ai.jeet.test.DataDownload.main(DataDownload.java:36)
When I run this API call via Postman I get a forbidden 403, but I also get an HTML response which says enable cookies and JavaScript.
I fail to understand how a server can differentiate between a web request call. Obviously, I am doing something wrong, but what is it?
The main difference from what I could see is the User Agent header value. The server might be checking for a few specific header values. I have one value working for me as shown below:
Request with 403
curl -v 'https://tvc4.investing.com/49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918' -H 'User-Agent: Mozilla' -o /dev/null
Response
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 2606:4700::6812:9a:443...
* Connected to tvc4.investing.com (2606:4700::6812:9a) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
} [323 bytes data]
* (304) (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* (304) (IN), TLS handshake, Unknown (8):
{ [19 bytes data]
* (304) (IN), TLS handshake, Certificate (11):
{ [2326 bytes data]
* (304) (IN), TLS handshake, CERT verify (15):
{ [80 bytes data]
* (304) (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* (304) (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=investing.com
* start date: Aug 1 00:00:00 2022 GMT
* expire date: Aug 1 23:59:59 2023 GMT
* subjectAltName: host "tvc4.investing.com" matched cert's "*.investing.com"
* issuer: C=US; O=Cloudflare, Inc.; CN=Cloudflare Inc ECC CA-3
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x137012600)
> GET /49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918 HTTP/2
> Host: tvc4.investing.com
> accept: */*
> user-agent: Mozilla
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 256)!
< HTTP/2 403
< date: Wed, 23 Nov 2022 14:22:29 GMT
< content-type: text/html; charset=UTF-8
< cache-control: max-age=15
< expires: Wed, 23 Nov 2022 14:22:44 GMT
< x-frame-options: SAMEORIGIN
< set-cookie: __cf_bm=uwoeNXvcnmEDY7ACRnFQEDqGZN4Yfx2_cyXbho.D6.M-1669213349-0-AUqobigV2idaMayGrBR+OdyTBo8pbjfS77vjhSh6bA4wiaBuz79/5kbwvXwD2loYoHJt1BsTguMEYh7WRm2ikPo=; path=/; expires=Wed, 23-Nov-22 14:52:29 GMT; domain=.investing.com; HttpOnly; Secure; SameSite=None
< server: cloudflare
< cf-ray: 76ea8eab8cbbb06a-ATL
< alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
<
{ [972 bytes data]
100 4537 0 4537 0 0 23760 0 --:--:-- --:--:-- --:--:-- 25346
* Connection #0 to host tvc4.investing.com left intact
Request with 200 Response
curl -v 'https://tvc4.investing.com/49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918' -H 'User-Agent: Mozilla/5.0' -o /dev/null
Response
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Trying 2606:4700::6812:19a:443...
* Connected to tvc4.investing.com (2606:4700::6812:19a) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
* CApath: none
* (304) (OUT), TLS handshake, Client hello (1):
} [323 bytes data]
* (304) (IN), TLS handshake, Server hello (2):
{ [122 bytes data]
* (304) (IN), TLS handshake, Unknown (8):
{ [19 bytes data]
* (304) (IN), TLS handshake, Certificate (11):
{ [2326 bytes data]
* (304) (IN), TLS handshake, CERT verify (15):
{ [79 bytes data]
* (304) (IN), TLS handshake, Finished (20):
{ [36 bytes data]
* (304) (OUT), TLS handshake, Finished (20):
} [36 bytes data]
* SSL connection using TLSv1.3 / AEAD-CHACHA20-POLY1305-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=US; ST=California; L=San Francisco; O=Cloudflare, Inc.; CN=investing.com
* start date: Aug 1 00:00:00 2022 GMT
* expire date: Aug 1 23:59:59 2023 GMT
* subjectAltName: host "tvc4.investing.com" matched cert's "*.investing.com"
* issuer: C=US; O=Cloudflare, Inc.; CN=Cloudflare Inc ECC CA-3
* SSL certificate verify ok.
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x13800b600)
> GET /49137b20ec52f5d1133789e270e21db8/1668879605/56/56/23/history?symbol=18325&resolution=5&from=1668448858&to=1668880918 HTTP/2
> Host: tvc4.investing.com
> accept: */*
> user-agent: Mozilla/5.0
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 256)!
< HTTP/2 200
< date: Wed, 23 Nov 2022 14:22:13 GMT
< content-type: text/html; charset=utf-8
< access-control-allow-origin: https://tvc-invdn-com.investing.com
< x-requested-with: XMLHttpRequest
< access-control-allow-methods: POST, GET, OPTIONS, PUT, DELETE
< access-control-allow-headers: Content-Type, Depth, User-Agent, X-File-Size, X-Requested-With, If-Modified-Since, X-File-Name, Cache-Control, accept, sessionid, x-csrftoken, content-type
< x-benchmark-1a: 0ms, mem alloc - 768.00Kb start
< x-benchmark-1b: 3ms, mem alloc - 1024.00Kb getPairIdBySymbol
< x-benchmark-1c: 3ms, mem alloc - 1024.00Kb getIntervalByResolution
< x-benchmark-1d: 15ms, mem alloc - 1024.00Kb getPairDataAndAttributes in TradingviewConnector::findCandles
< x-benchmark-1e: 23ms, mem alloc - 3.50Mb getCandles in TradingviewConnector::findCandles
< x-benchmark-1f: 24ms, mem alloc - 3.75Mb end of TradingviewConnector::findCandles
< x-benchmark-1g: 25ms, mem alloc - 3.50Mb findCandles
< vary: Accept-Encoding,User-Agent
< content-security-policy: upgrade-insecure-requests; block-all-mixed-content
< cf-cache-status: DYNAMIC
< set-cookie: __cf_bm=z7PZf80TAcglrPBqnAC0p4ApGjbAfRvCP6uZDBinzzs-1669213333-0-AYMziboPajXlvpP44SA/dGfK246VFdm8eaSnco06Ug7FiLfKcTheS1UjW4S8yD0EEJFSW7kqengoBx6dH8W7YLg=; path=/; expires=Wed, 23-Nov-22 14:52:13 GMT; domain=.investing.com; HttpOnly; Secure; SameSite=None
< server: cloudflare
< cf-ray: 76ea8e461cc9ad68-ATL
< alt-svc: h3=":443"; ma=86400, h3-29=":443"; ma=86400
<
{ [314 bytes data]
100 19882 0 19882 0 0 61780 0 --:--:-- --:--:-- --:--:-- 62719
* Connection #0 to host tvc4.investing.com left intact

Jersey framework resource response issue Chunked-Encoded data

I'm am developing an application with the Jersey framework that acts as a proxy to the docker HTTP API. I'm able to upload images successfully to Docker but I am unable to forward the response from Docker to the client without an error. I believe it has something to do with the Transfer-Encoding=[chunked] header in the response.
Response
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /proxy/images/load HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 127.0.0.1:8080
> Accept: */*
> Content-Type: application/octet-stream
> Content-Length: 477637632
> Expect: 100-continue
>
< HTTP/1.1 100
< HTTP/1.1 200
< Transfer-Encoding: chunked
< Docker-Experimental: false
< Api-Version: 1.26
< Server: Docker/1.13.1 (linux)
< Date: Mon, 23 Jul 2018 11:20:14 GMT
< Content-Type: application/json
< Content-Length: 54
<
* Problem (2) in the Chunked-Encoded data
* Closing connection 0
curl: (56) Problem (2) in the Chunked-Encoded data
code
#POST
#Path("/load2")
//#Consumes(MediaType.APPLICATION_OCTET_STREAM)
public Response loadimages(byte[] input, #Context UriInfo uriInfo) {
WebTarget webTarget = ClientBuilder.newClient().target("http://127.0.0.1:5555/images").path("load");
Response response = webTarget.request(MediaType.APPLICATION_JSON).post(Entity.entity(input, MediaType.APPLICATION_OCTET_STREAM));
return response;
}

Spring boot request hang there when return 1xx status code

I have a small demo to play with customized status code.
The interesting part is the request will always hang there if the status is below 200, like 105, 199, etc. But works for any status greater than 200, like 209, 789 etc.
Http status code registry, refer to https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
Spring boot: 1.5.4.RELEASE with embedded tomcat
Java: 8
Controller:
#RestController
public class DemoController {
#GetMapping("/hello")
public ResponseEntity get() {
return ResponseEntity.status(105).build();
}
}
Can anyone give me a clear explanation?
I create a gist at here: https://gist.github.com/pengisgood/dbea1fcdc45c2bb5809871c7f020b800
Update:
I also create a small demo to reproduce it at here:
https://github.com/pengisgood/springboot-customize-status-code
Update:
After I run curl -v localhost:8080/hello, I can see the status, but the response doesn't finish. Refer to the gif below:
I also ran into this issue and found that it is not Spring that creates this behavior. It is Tomcat.
curl -v --header "Expect: 100-continue" http://localhost:8080
Calling any configured endpoint like this will return an extra response code that doesn't terminate the request.
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0*
Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET / HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.56.1
> Accept: */*
> Expect: 100-continue
>
< HTTP/1.1 100
< HTTP/1.1 200
< Set-Cookie: JSESSIONID=9355141A10CF546E9A9A43F5A5C0B1A4; Path=/; HttpOnly
< Content-Type: text/html;charset=ISO-8859-1
< Content-Length: 58
< Date: Tue, 31 Jul 2018 17:27:52 GMT
<
{ [58 bytes data]
100 58 100 58 0 0 58 0 0:00:01 --:--:-- 0:00:01 82<html>
<body>
<h2>Hello Heroku!</h2>
</body>
</html>
* Connection #0 to host localhost left intact
note the HTTP/1.1 100
This response came from this project https://devcenter.heroku.com/articles/create-a-java-web-application-using-embedded-tomcat which doesn't have spring. If I modify the HelloServlet to include a response code of 100 it just hangs.
Looking deeper:
https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html#sec8.2.3
The specification makes it clear that the 100 response is supposed to happen in the same request. The reason it hangs is because it is expecting the client to respond with the content of the request.
Looking at the wiki for other 1XX response codes, it appears to also be true that some information is returned without closing the request. My guess is that Tomcat expects all 1xx response codes to act in this manner.
As far as I can tell the Spring DispacherServlet is handling the different return codes in exactly the same way. I think what's happening is curl is just leaving the connection open because the response is in the 1xx range.
This article provides a good primer on status codes. This sentence in particular is relevant:
100–199 Codes in the 100s are informational, indicating that the client should respond with some other action.
If you run curl with --trace you'll see that the 105 response does actually arrive:
curl -v -trace http://localhost:8080/hello
Trying ::1...
TCP_NODELAY set
Connected to localhost (::1) port 8080 (#0)
> GET /hello HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 105
< Date: Tue, 19 Sep 2017 18:07:04 GMT
^C
So what I think is happening is the response is returned, the client should respond with some other action (but doesn't) so it looks like the thing has hung.
Probably the real question here is why are you trying to return a 105 status and what do you expect to happen?

Why is Spring Boot handling a "404 Not Found" for entities differently?

I am wondering why Spring Boot is handling 404 Not Found differently.
None existing path example
I make a request on a none existing path with curl:
$ curl -v -H "Authorization: Basic YWRtaW46YWRtaW4xMjM=" http://localhost:8080/no/endpoint | python -m json.tool
* Adding handle: conn: 0x69aa30
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x69aa30) send_pipe: 1, recv_pipe: 0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /no/endpoint HTTP/1.1
> User-Agent: curl/7.33.0
> Host: localhost:8080
> Accept: */*
> Authorization: Basic YWRtaW46YWRtaW4xMjM=
>
< HTTP/1.1 404
< Set-Cookie: JSESSIONID=62B5B02F18842F3BD46BCE57F2EAB017;path=/;HttpOnly
< X-Application-Context: Rechnungsservice Gateway:dev
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Mon, 20 Feb 2017 11:59:19 GMT
<
{ [data not shown]
100 115 0 115 0 0 569 0 --:--:-- --:--:-- --:--:-- 614
* Connection #0 to host localhost left intact
{
"error": "Not Found",
"message": "No message available",
"path": "/no/endpoint",
"status": 404,
"timestamp": 1487591959599
}
Same operation with a browser:
And now I request an endpoint for an none existing entity:
$ curl -v -H "Authorization: Basic YWRtaW46YWRtaW4xMjM=" http://localhost:8080/api/v1/settings/123 | python -m json.tool
* Adding handle: conn: 0x62aa40
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x62aa40) send_pipe: 1, recv_pipe: 0
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* About to connect() to localhost port 8
080 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api/v1/settings/123 HTTP/1.1
> User-Agent: curl/7.33.0
> Host: localhost:8080
> Accept: */*
> Authorization: Basic YWRtaW46YWRtaW4xMjM=
>
< HTTP/1.1 404
< Set-Cookie: JSESSIONID=BCD5ADDA48EB03C235E6573A36860F7D;path=/;HttpOnly
< X-Application-Context: Rechnungsservice Gateway:dev
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Content-Length: 0
< Date: Mon, 20 Feb 2017 12:05:29 GMT
<
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
* Connection #0 to host localhost left intact
No JSON object could be decoded
Same operation in browser:
So my question is: Why is Spring Boot only sending a simple 404 Status in case of the not found entity? I would like to see a nice message: Entity not found or something like this on my error page for text/html or a json error object in case of a json request... For the path example it is working like a charm out of the box...
I am using Spring Boot 1.4.3.RELEASE.
UPDATE:
Sorry I forgot to say that I am using Spring Data Rest.
And here I debugged unti I found this code snippet:
class RepositoryEntityController ... {
public ResponseEntity<Resource<?>> getItemResource(...) {
Object domainObj = getItemResource(resourceInformation, id);
if (domainObj == null) {
return new ResponseEntity<Resource<?>>(HttpStatus.NOT_FOUND);
}
}
In my opinion a request to a single entity that doesn't exists should throw a "NotFoundException", leading to a better response.
The first request never reaches your Spring application, your WAR is not deployed at that location, so instead you get the generic 404 message from the web server (Tomcat perhaps).

Jetty doesn't close connection

I've created a simple server Java application using Gradle. As an embedded server , I am using Jetty . I am also using a Gretty plugin as it supports the latest Jetty version.
The project runs just fine . And I have tried to stress test it. As a part of my test I need to check the response time and therefore I am sending "Connection:Close" header via curl.
My response is a long JSON string , and I see only part of it , after which the connection hangs . I would like to know Why is it happening , and how can I work around it.
NOTE :
When sending Connection:Keep-alive header , everything is fine
When response from the server is not a long string , but smaller . It works just fine (doesn't hang)
Tried the standard Jetty plugin from gradle , the result was the same.
HOW TO TEST :
Build and run my project from console ./gradlew appRun
From bash console run curl -H "Connection:Close" -i "http://localhost:8080/Environment/example"
See the partial response and the connection still alive...
Seems like you are confusing the persistent connection modes between HTTP/1.0 and HTTP/1.1.
Either that, or you are using a really old version of curl that still defaults to HTTP/1.0.
HTTP/1.0 has no persistent connections by default, so to use persistent connections we send Connection: keep-alive.
HTTP/1.1 uses persistent connections by default, so to disable it we can send Connection: close
Using HTTP/1.0, with Connection: close is like sending this ...
GET /Environment/example HTTP/1.0
Host: localhost:8080
Connection: close
... which produces an invalid header value for Connection per the HTTP/1.0 spec
Lets use the verbose features of curl to see what's really going on Connection wise...
Example: HTTP/1.1 with normal operation:
$ curl --verbose --http1.1 http://apache.org/ -so /dev/null
* Trying 88.198.26.2...
* Connected to apache.org (88.198.26.2) port 80 (#0)
> GET / HTTP/1.1
> Host: apache.org
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 06 May 2016 12:05:39 GMT
< Server: Apache/2.4.7 (Ubuntu)
< Last-Modified: Fri, 06 May 2016 11:10:20 GMT
< ETag: "cf64-5322a812896a8"
< Accept-Ranges: bytes
< Content-Length: 53092
< Vary: Accept-Encoding
< Cache-Control: max-age=3600
< Expires: Fri, 06 May 2016 13:05:39 GMT
< Content-Type: text/html
<
{ [1125 bytes data]
* Connection #0 to host apache.org left intact
Notice that it says it kept the connection intact?
Example: HTTP/1.1 with manual Connection: close operation:
$ curl --verbose --http1.1 --header "Connection: close" http://apache.org/ -so /dev/null
* Trying 140.211.11.105...
* Connected to apache.org (140.211.11.105) port 80 (#0)
> GET / HTTP/1.1
> Host: apache.org
> User-Agent: curl/7.43.0
> Accept: */*
> Connection: close
>
< HTTP/1.1 200 OK
< Date: Fri, 06 May 2016 12:06:35 GMT
< Server: Apache/2.4.7 (Ubuntu)
< Last-Modified: Fri, 06 May 2016 11:10:20 GMT
< ETag: "cf64-5322a812896a8"
< Accept-Ranges: bytes
< Content-Length: 53092
< Vary: Accept-Encoding
< Cache-Control: max-age=3600
< Expires: Fri, 06 May 2016 13:06:35 GMT
< Connection: close
< Content-Type: text/html
<
{ [1106 bytes data]
* Closing connection 0
Ah, the HTTP response headers say that the server will close, and curl saw the connection being closed. What we wanted.
Example: HTTP/1.0 with normal operation:
$ curl --verbose --http1.0 http://apache.org/ -so /dev/null
* Trying 140.211.11.105...
* Connected to apache.org (140.211.11.105) port 80 (#0)
> GET / HTTP/1.0
> Host: apache.org
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 06 May 2016 12:08:27 GMT
< Server: Apache/2.4.7 (Ubuntu)
< Last-Modified: Fri, 06 May 2016 11:10:20 GMT
< ETag: "cf64-5322a812896a8"
< Accept-Ranges: bytes
< Content-Length: 53092
< Vary: Accept-Encoding
< Cache-Control: max-age=3600
< Expires: Fri, 06 May 2016 13:08:27 GMT
< Connection: close
< Content-Type: text/html
<
{ [4002 bytes data]
* Closing connection 0
See how the HTTP response headers say that the server will close?
Curl also saw the connection being closed.
That's what we expect with normal HTTP/1.0 operation.
Example: HTTP/1.0 with persistent connection:
$ curl --verbose --http1.0 --header "Connection: keep-alive" http://apache.org/ -so /dev/null
* Trying 88.198.26.2...
* Connected to apache.org (88.198.26.2) port 80 (#0)
> GET / HTTP/1.0
> Host: apache.org
> User-Agent: curl/7.43.0
> Accept: */*
> Connection: keep-alive
>
< HTTP/1.1 200 OK
< Date: Fri, 06 May 2016 12:08:37 GMT
< Server: Apache/2.4.7 (Ubuntu)
< Last-Modified: Fri, 06 May 2016 11:10:20 GMT
< ETag: "cf64-5322a812896a8"
< Accept-Ranges: bytes
< Content-Length: 53092
< Vary: Accept-Encoding
< Cache-Control: max-age=3600
< Expires: Fri, 06 May 2016 13:08:37 GMT
< Keep-Alive: timeout=30, max=100
< Connection: Keep-Alive
< Content-Type: text/html
<
{ [3964 bytes data]
* Connection #0 to host apache.org left intact
Yup, the server indicates that it will use Keep-Alive too (per HTTP/1.0 spec), and curl even concurs and says the connection is left intact.

Categories