Hi folks,

right away, I don't know whether it is us (Tomcat) or curl. I'd lke to narrow down the cause.

I am trying to enable HTTP/2 for some upload services via Tomcat directly (HTTPd is currently out of scope here).

I am running off:

Server version:        Apache Tomcat/8.5.38
> Server built:          Feb 5 2019 11:42:42 UTC
> Server number:         8.5.38.0
> OS Name:               FreeBSD
> OS Version:            12.0-STABLE
> Architecture:          amd64
> Java Home:             /usr/local/openjdk8/jre
> JVM Version:           1.8.0_202-b08
> JVM Vendor:            Oracle Corporation
>
> Loaded APR based Apache Tomcat Native library [1.2.21] using APR version [1.6.5]. > capabilities: IPv6 [true], sendfile [true], accept filters [true], random [true].
> APR/OpenSSL configuration: useAprConnector [true], useOpenSSL [true]
> OpenSSL successfully initialized [OpenSSL 1.1.1a-freebsd  20 Nov 2018]
>
> <Connector address="147.54.64.55" port="8445" connectionTimeout="20000"
>   maxHttpHeaderSize="24576" maxThreads="250"
>   SSLEnabled="true" scheme="https" secure="true"
>   defaultSSLHostConfigName="sitex-ldadw.ad001.siemens.net">
>   <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
> <SSLHostConfig hostName="sitex-ldadw.ad001.siemens.net" protocols="TLSv1.2+TLSv1.3" > honorCipherOrder="true" ciphers="HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK:!DSS"> > <Certificate certificateFile="/etc/ssl/sitex-ldadw.ad001.siemens.net/cert/public.pem" > certificateKeyFile="/etc/ssl/sitex-ldadw.ad001.siemens.net/key/private.pem"
>       certificateKeyPassword="..."
>       type="RSA" />
>   </SSLHostConfig>
> </Connector>
>
> $ curl --version
> curl 7.64.0 (amd64-portbld-freebsd12.0) libcurl/7.64.0 OpenSSL/1.1.1b zlib/1.2.11 nghttp2/1.37.0
> Release-Date: 2019-02-06
> Protocols: file http https rtsp smtp smtps
> Features: AsynchDNS Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz HTTP2 UnixSockets HTTPS-proxy

Now trying to upload a WAR file to the manager, with curl for example, fails
(while it works with HTTP/1.1 flawlessly for years):

> $ time curl --verbose -H 'Expect: 100-continue' --negotiate -u : --upload-file target/lda-docgen-webapp-0.1-SNAPSHOT-backend-dev.war -o manager-response.txt 'https://sitex-ldadw.ad001.siemens.net:8445/backend-dev/manager-1/text/deploy?path=/backend-dev&update=false&version=003'
> * Expire in 0 ms for 6 (transfer 0x800d65000)
> * Uses proxy env variable NO_PROXY == 'localhost .siemens.net .siemens.com .siemens.de'
> * Expire in 1 ms for 1 (transfer 0x800d65000)
> % Total % Received % Xferd Average Speed Time Time Time Current > Dload Upload Total Spent Left Speed > 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Expire in 0 ms for 1 (transfer 0x800d65000)
> * Expire in 1 ms for 1 (transfer 0x800d65000)
> ...
> *   Trying 147.54.64.55...
> * TCP_NODELAY set
> * Expire in 200 ms for 4 (transfer 0x800d65000)
> * Connected to sitex-ldadw.ad001.siemens.net (147.54.64.55) port 8445 (#0)
> * ALPN, offering h2
> * ALPN, offering http/1.1
> * successfully set certificate verify locations:
> *   CAfile: /usr/local/etc/ssl/cert.pem
>   CApath: none
> } [5 bytes data]
> * TLSv1.3 (OUT), TLS handshake, Client hello (1):
> } [512 bytes data]
> * TLSv1.3 (IN), TLS handshake, Server hello (2):
> { [122 bytes data]
> * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
> { [19 bytes data]
> * TLSv1.3 (IN), TLS handshake, Certificate (11):
> { [6195 bytes data]
> * TLSv1.3 (IN), TLS handshake, CERT verify (15):
> { [520 bytes data]
> * TLSv1.3 (IN), TLS handshake, Finished (20):
> { [52 bytes data]
> * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
> } [1 bytes data]
> * TLSv1.3 (OUT), TLS handshake, Finished (20):
> } [52 bytes data]
> * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
> * ALPN, server accepted to use h2
> * Server certificate:
> *  subject: C=DE; O=Siemens; OU=LDA DW; CN=sitex-ldadw.ad001.siemens.net
> *  start date: Mar 19 13:10:13 2019 GMT
> *  expire date: Mar 19 13:10:13 2020 GMT
> * subjectAltName: host "sitex-ldadw.ad001.siemens.net" matched cert's "sitex-ldadw.ad001.siemens.net" > * issuer: C=DE; ST=Bayern; L=Muenchen; O=Siemens; serialNumber=ZZZZZZB7; OU=Siemens Trust Center; CN=Siemens Issuing CA Intranet Server 2017
> *  SSL certificate verify ok.
> * Using HTTP2, server supports multi-use
> * Connection state changed (HTTP/2 confirmed)
> * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
> } [5 bytes data]
> * Using Stream ID: 1 (easy handle 0x800d65000)
> } [5 bytes data]
> > PUT /backend-dev/manager-1/text/deploy?path=/backend-dev&update=false&version=003 HTTP/2
> > Host: sitex-ldadw.ad001.siemens.net:8445
> > User-Agent: curl/7.64.0
> > Accept: */*
> > Expect: 100-continue
> > Content-Length: 6502195
> >
> { [5 bytes data]
> * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
> { [281 bytes data]
> * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
> { [281 bytes data]
> * old SSL session ID is stale, removing
> } [5 bytes data]
> * Connection state changed (MAX_CONCURRENT_STREAMS == 200)!
> } [5 bytes data]
> < HTTP/2 401
> < cache-control: private
> < expires: Thu, 01 Jan 1970 00:00:00 GMT
> < www-authenticate: Negotiate
> < content-type: text/html;charset=utf-8
> < content-language: en
> < content-length: 802
> < date: Thu, 28 Mar 2019 13:48:19 GMT
> * HTTP error before end of send, stop sending
> <
> { [5 bytes data]
> * Ignoring the response-body
> { [802 bytes data]
> 1 6349k 0 0 1 65535 0 1185k 0:00:05 --:--:-- 0:00:05 1185k
> * Connection #0 to host sitex-ldadw.ad001.siemens.net left intact
> * Issue another request to this URL: 'https://sitex-ldadw.ad001.siemens.net:8445/backend-dev/manager-1/text/deploy?path=/backend-dev&update=false&version=003' > * Uses proxy env variable NO_PROXY == 'localhost .siemens.net .siemens.com .siemens.de' > * Found bundle for host sitex-ldadw.ad001.siemens.net: 0x800cd5270 [can multiplex] > * Re-using existing connection! (#0) with host sitex-ldadw.ad001.siemens.net > * Connected to sitex-ldadw.ad001.siemens.net (147.54.64.55) port 8445 (#0)
> * Server auth using Negotiate with user ''
> * Using Stream ID: 3 (easy handle 0x800d65000)
> } [5 bytes data]
> > PUT /backend-dev/manager-1/text/deploy?path=/backend-dev&update=false&version=003 HTTP/2
> > Host: sitex-ldadw.ad001.siemens.net:8445
> > Authorization: Negotiate YIISIwYGKwY...
> > User-Agent: curl/7.64.0
> > Accept: */*
> > Expect: 100-continue
> > Content-Length: 6502195
> >
> } [0 bytes data]
> 0 6349k 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0< HTTP/2 100
> } [0 bytes data]
> 0 6349k 0 0 0 0 0 0 --:--:-- 0:00:20 --:--:-- 0< HTTP/2 200
> < cache-control: private
> < expires: Thu, 01 Jan 1970 00:00:00 GMT
> < www-authenticate: Negotiate oYHzMIHwo...
> < x-content-type-options: nosniff
> < content-type: text/plain;charset=utf-8
> < date: Thu, 28 Mar 2019 13:48:39 GMT
> <
> } [0 bytes data]
> * HTTP/2 stream 0 was not closed cleanly: ENHANCE_YOUR_CALM (err 11)
> * stopped the pause stream!
> 0 6349k 0 161 0 0 7 0 --:--:-- 0:00:21 --:--:-- 33
> * Connection #0 to host sitex-ldadw.ad001.siemens.net left intact
> curl: (92) HTTP/2 stream 0 was not closed cleanly: ENHANCE_YOUR_CALM (err 11)
>
> real    0m21,019s
> user    0m9,054s
> sys     0m11,950s
> $ less manager-response.txt
> FAIL - Encountered exception [org.apache.catalina.connector.ClientAbortException: org.apache.coyote.CloseNowException: Timeout waiting to read data from client]

and Tomcat says:

> 2019-03-28T14:48:19.976 INFO [https-openssl-apr-147.54.64.55-8445-exec-9] org.apache.catalina.core.ApplicationContext.log Manager: deploy: Deploying web application '/backend-dev##003' > 2019-03-28T14:48:19.976 INFO [https-openssl-apr-147.54.64.55-8445-exec-9] org.apache.catalina.core.ApplicationContext.log Manager: Uploading WAR file to /usr/local/ldadocgen/backend-dev/tomcat-1/webapps/backend- > 2019-03-28T14:48:39.979 SEVERE [https-openssl-apr-147.54.64.55-8445-exec-9] org.apache.catalina.core.ApplicationContext.log Manager: managerServlet.check[/backend-dev##003] > org.apache.catalina.connector.ClientAbortException: org.apache.coyote.CloseNowException: Timeout waiting to read data from client > at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:348) > at org.apache.catalina.connector.InputBuffer.checkByteBufferEof(InputBuffer.java:663) > at org.apache.catalina.connector.InputBuffer.read(InputBuffer.java:370) > at org.apache.catalina.connector.CoyoteInputStream.read(CoyoteInputStream.java:152) > at org.apache.catalina.manager.ManagerServlet.uploadWar(ManagerServlet.java:1668) > at org.apache.catalina.manager.ManagerServlet.deploy(ManagerServlet.java:798) > at org.apache.catalina.manager.ManagerServlet.doPut(ManagerServlet.java:448)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:664)
>     at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
> at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) > at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) > at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) > at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) > at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) > at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:109) > at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) > at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) > at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) > at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) > at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:610) > at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) > at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) > at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650) > at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:679) > at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) > at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) > at org.apache.coyote.http2.StreamProcessor.service(StreamProcessor.java:317) > at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) > at org.apache.coyote.http2.StreamProcessor.process(StreamProcessor.java:69)
>     at org.apache.coyote.http2.StreamRunnable.run(StreamRunnable.java:35)
> at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) > at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) > at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
>     at java.lang.Thread.run(Thread.java:748)
> Caused by: org.apache.coyote.CloseNowException: Timeout waiting to read data from client > at org.apache.coyote.http2.Stream$StreamInputBuffer.doRead(Stream.java:1086)
>     at org.apache.coyote.Request.doRead(Request.java:581)
> at org.apache.catalina.connector.InputBuffer.realReadBytes(InputBuffer.java:344)
>     ... 33 more
> Caused by: org.apache.coyote.http2.StreamException: Timeout waiting to read data from client > at org.apache.coyote.http2.Stream$StreamInputBuffer.doRead(Stream.java:1081)
>     ... 35 more

Removing "Expect: 100-continue" makes no difference here.

Doing the same with HTTPd 2.4.38 with mod_cgid and a Python script:
> $ less upload.py
> #!/usr/bin/env python3
>
> import cgi
> import cgitb; cgitb.enable()
> import os
> import sys
> import shutil
>
> if os.environ['REQUEST_METHOD'] == 'PUT':
>     print("Status: 204")
>     print()
>     data = sys.stdin.buffer.read()
>     with open('/tmp/upload.bin', 'wb+') as outfile:
>         outfile.write(data)
> else:
>     print("Status: 405")
>     print()


> $ time curl --verbose --negotiate -u : --upload-file target/lda-docgen-webapp-0.1-SNAPSHOT-backend-dev.war 'https://sitex-ldadw.ad001.siemens.net/webhooks/upload.py' -H "Expect: 100-continue"
> * Expire in 0 ms for 6 (transfer 0x800d65000)
> * Uses proxy env variable NO_PROXY == 'localhost .siemens.net .siemens.com .siemens.de'
> * Expire in 1 ms for 1 (transfer 0x800d65000)
> % Total % Received % Xferd Average Speed Time Time Time Current > Dload Upload Total Spent Left Speed > 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0* Expire in 0 ms for 1 (transfer 0x800d65000)
> * Expire in 1 ms for 1 (transfer 0x800d65000)
> ...
> *   Trying 147.54.64.55...
> * TCP_NODELAY set
> * Expire in 200 ms for 4 (transfer 0x800d65000)
> * Connected to sitex-ldadw.ad001.siemens.net (147.54.64.55) port 443 (#0)
> * ALPN, offering h2
> * ALPN, offering http/1.1
> * successfully set certificate verify locations:
> *   CAfile: /usr/local/etc/ssl/cert.pem
>   CApath: none
> } [5 bytes data]
> * TLSv1.3 (OUT), TLS handshake, Client hello (1):
> } [512 bytes data]
> * TLSv1.3 (IN), TLS handshake, Server hello (2):
> { [122 bytes data]
> * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
> { [19 bytes data]
> * TLSv1.3 (IN), TLS handshake, Certificate (11):
> { [6195 bytes data]
> * TLSv1.3 (IN), TLS handshake, CERT verify (15):
> { [520 bytes data]
> * TLSv1.3 (IN), TLS handshake, Finished (20):
> { [52 bytes data]
> * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
> } [1 bytes data]
> * TLSv1.3 (OUT), TLS handshake, Finished (20):
> } [52 bytes data]
> * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
> * ALPN, server accepted to use h2
> * Server certificate:
> *  subject: C=DE; O=Siemens; OU=LDA DW; CN=sitex-ldadw.ad001.siemens.net
> *  start date: Mar 19 13:10:13 2019 GMT
> *  expire date: Mar 19 13:10:13 2020 GMT
> * subjectAltName: host "sitex-ldadw.ad001.siemens.net" matched cert's "sitex-ldadw.ad001.siemens.net" > * issuer: C=DE; ST=Bayern; L=Muenchen; O=Siemens; serialNumber=ZZZZZZB7; OU=Siemens Trust Center; CN=Siemens Issuing CA Intranet Server 2017
> *  SSL certificate verify ok.
> * Using HTTP2, server supports multi-use
> * Connection state changed (HTTP/2 confirmed)
> * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
> } [5 bytes data]
> * Using Stream ID: 1 (easy handle 0x800d65000)
> } [5 bytes data]
> > PUT /webhooks/upload.py HTTP/2
> > Host: sitex-ldadw.ad001.siemens.net
> > User-Agent: curl/7.64.0
> > Accept: */*
> > Expect: 100-continue
> > Content-Length: 6502195
> >
> { [5 bytes data]
> * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
> { [297 bytes data]
> * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
> { [297 bytes data]
> * old SSL session ID is stale, removing
> { [5 bytes data]
> * Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
> } [5 bytes data]
> < HTTP/2 401
> < date: Thu, 28 Mar 2019 14:36:56 GMT
> < server: Apache/2.4.38 (FreeBSD) OpenSSL/1.1.1a-freebsd mod_auth_gssapi/1.6.1
> < x-frame-options: SAMEORIGIN
> < www-authenticate: Negotiate
> < content-length: 523
> < content-type: text/html; charset=iso-8859-1
> * HTTP error before end of send, stop sending
> <
> * Ignoring the response-body
> { [523 bytes data]
> 1 6349k 0 0 1 65535 0 1230k 0:00:05 --:--:-- 0:00:05 1254k
> * Connection #0 to host sitex-ldadw.ad001.siemens.net left intact
> * Issue another request to this URL: 'https://sitex-ldadw.ad001.siemens.net/webhooks/upload.py' > * Uses proxy env variable NO_PROXY == 'localhost .siemens.net .siemens.com .siemens.de' > * Found bundle for host sitex-ldadw.ad001.siemens.net: 0x800cd5390 [can multiplex] > * Re-using existing connection! (#0) with host sitex-ldadw.ad001.siemens.net
> * Connected to sitex-ldadw.ad001.siemens.net (147.54.64.55) port 443 (#0)
> * Server auth using Negotiate with user ''
> * Using Stream ID: 3 (easy handle 0x800d65000)
> } [5 bytes data]
> > PUT /webhooks/upload.py HTTP/2
> > Host: sitex-ldadw.ad001.siemens.net
> > Authorization: Negotiate YIISJQYGKwYBBQUCoI...
> > User-Agent: curl/7.64.0
> > Accept: */*
> > Expect: 100-continue
> > Content-Length: 6502195
> >
> } [5 bytes data]
> < HTTP/2 100
> } [5 bytes data]
> 3 6349k 0 0 3 191k 0 1432k 0:00:04 --:--:-- 0:00:04 1432k* We are completely uploaded and fine
> { [5 bytes data]
> < HTTP/2 204
> < date: Thu, 28 Mar 2019 14:36:56 GMT
> < server: Apache/2.4.38 (FreeBSD) OpenSSL/1.1.1a-freebsd mod_auth_gssapi/1.6.1
> < www-authenticate: Negotiate oYG3MIG0oAMKA...
> < x-frame-options: SAMEORIGIN
> <
> { [5 bytes data]
> 100 6349k 0 0 100 6349k 0 15.3M --:--:-- --:--:-- --:--:-- 22.2M
> * Connection #0 to host sitex-ldadw.ad001.siemens.net left intact
>
> real    0m0,420s
> user    0m0,212s
> sys     0m0,169s

It works, even without "Expect: 100-continue".
As far as I understand the HTTP/2 spec, the header is not necessary anymore and this is builtin into the protocol.

Any ideas?

Michael

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to