282

I am getting below stack trace when I am deploying my application in a multi-server Apache Tomcat 8 environment. I am getting this error frequently, and it seems it is blocking the tomcat thread:

INFO [http-nio-80-exec-4461] org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
 java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens
 at org.apache.coyote.http11.AbstractNioInputBuffer.parseRequestLine(AbstractNioInputBuffer.java:233)
 at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1017)
 at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1524)
 at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1480)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Unknown Source)

Can any one direct me how to troubleshoot or narrow down such an exeption? I am not getting any reference to any of my application source files. I tried to google around, and in of the links it said, you are trying to access http url through https, which seems unlikely. I am not getting this error, when the application runs on a single Tomcat 8 instance. I get this only in a multi-server environment.

I am also sharing the meta tags I have embedded on each page, if that helps to identify the cause.

<%
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Cache-Control", "no-store");
    response.setDateHeader("Expires", 0);
    response.setHeader("Pragma", "no-cache");
%>


<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1">

I am also using the following in a few pages, which basically is same as above:

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Cache-Control" content="private" />
<meta http-equiv="Cache-Control" content="no-store" />
<meta http-equiv="Pragma" content="no-cache" />

Even if anyone helps in giving a direction to my troubleshooting attempt, that will be useful, as currently I have no idea where to look into.

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
user2016012
  • 2,929
  • 2
  • 13
  • 4

17 Answers17

468

This exception can occur when you try to execute HTTPS request from client on endpoint which isn't HTTPS enabled. Client will encrypt request data when server is expecting raw data.

naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
Petar Tonev
  • 4,761
  • 1
  • 8
  • 14
  • 4
    I'm not sure I understand this answer. I have a Spring Boot 1.5.1 app and I saw this exception in my log. My app only answers for SSL on port 8443 (redirected from port 443) and only has the one connector for SSL. Are you saying that someone could try http: instead of https: on port 443? – Jim Archer Mar 14 '17 at 16:00
  • 6
    Such an exceptions happen when there is a mismatch between what the server expects and what it gets. What you said is one of the possible scenarios. Maybe there is an endpoint in your server that does not run on https, but someone tries to access it this way? – Petar Tonev Mar 15 '17 at 16:15
  • 2
    Hi Peter... The issue ended up being that someone created an IP Tables rule to forward port 80 to port 8443, so anyone who hit the site using http on port 80 caused that error. We added a Tomcat connector to redirect port 8080 to 8443 and set up IP Tables rule to forward port 80 to port 8080 and the problem is all but gone. Thank for for your reply! – Jim Archer Mar 15 '17 at 17:37
  • 2
    @PeterTonev: Any idea how to (redirect https to http || disable https || catch the error to at least show a meaningful error message)? – crusy May 12 '17 at 07:04
  • 1
    @crusy Something that may help you here for the exception handling is [link](http://stackoverflow.com/questions/23580509/how-to-write-a-proper-global-error-handler-with-spring-mvc-spring-boot) – Petar Tonev May 22 '17 at 10:33
  • just stumbled over this and the problem was exactly as @PeterTonev described, thanks! changing to http solved the problem, just an oversight. – Gregor Jan 29 '18 at 16:37
  • This answer does not provide a solution to the problem, it only points it out. – FARS Sep 15 '22 at 17:11
126

I got the same exception when I locally tested. The problem was a URL schema in my request.

Change https to http in your client URL.

Probably it will helps.

Priyantha
  • 4,839
  • 6
  • 26
  • 46
28

You are calling local server with http://localhost:8080/foo/bar. Call it with https://localhost:8080/foo/bar. This solves the problem

Shivan Sawant
  • 509
  • 5
  • 9
  • 4
    Probably you won't have https:// on 8080. Change the call to **https://** localhost:8443/foo/bar - Here is the example [link](https://dzone.com/articles/setting-ssl-tomcat-5-minutes) – Rodrigo R. Coelho – Rodrigo R. Coelho Jan 25 '20 at 00:52
  • 1
    Exactly the opposite - must change **https** to **http** – Václav Jul 04 '23 at 14:56
26

In case someone is using swagger:

Change the Scheme to HTTP or HTTPS, depend on needs, prior to hit the execute.

Postman:

Change the URL Path to http:// or https:// in the url address

Cyber
  • 2,194
  • 4
  • 22
  • 41
  • In my case https://localhost:8080/index https : with(s) was not working and http://localhost:8080/index (http without s) was working , I have no idea why this was happening ? Do we have to enable SSL manually to run at https ? – Badri Paudel Oct 13 '20 at 11:14
12

I received this exception unrelated to any TLS issues. In my case the Content-Length header value did not match the body length.

mibollma
  • 14,959
  • 6
  • 52
  • 69
  • 4
    I can't thank you enough. Every other POST request was failing with error 400, and I was ready to rip my hair out. Turned out that not sending `content-length` header solves this issue. – Alexander Woodblock Jul 09 '19 at 15:43
  • 3
    I was getting a delay of 30-90sec for Postman requests to local dev - turns out, it was this issue! Disabling the `Content-Length` header fixed the delay. – Alok Jan 09 '20 at 20:22
5

I know this is an old thread, but there is a particular case when this may happen:

If you are using AWS api gateway coupled with a VPC link, and if the Network Load Balancer has proxy protocol v2 enabled, a 400 Bad Request will happen as well.

Took me the whole afternoon to figure it out, so if it may help someone I'd be glad :)

Daniel
  • 807
  • 8
  • 24
3

In my case I had to clear browser history/cookies to get rid of this error.

rustylepord
  • 5,681
  • 6
  • 36
  • 49
3

I had this issue when working on a Java Project in Debian 10 with Tomcat as the application server.

The issue was that the application already had https defined as it's default protocol while I was using http to call the application in the browser. So when I try running the application I get this error in my log file:

INFO [http-nio-80-exec-4461] org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header

Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.

java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens

I however tried using the https protocol in the browser but it didn't connect throwing the error:

Here's how I solved it:

You need a certificate to setup the https protocol for the application. You can obtain certificates from Let's Encrypt. For me the easiest route was creating a obtaining a self-signed certificate. .

I first had to create a keystore file for the application, more like a self-signed certificate for the https protocol:

sudo keytool -genkey -keyalg RSA -alias tomcat -keystore /usr/share/tomcat.keystore

Note: You need to have Java installed on the server to be able to do this. Java can be installed using sudo apt install default-jdk.

Next, I added a https Tomcat server connector for the application in the Tomcat server configuration file (/opt/tomcat/conf/server.xml):

sudo nano /opt/tomcat/conf/server.xml

Add the following to the configuration of the application. Notice that the keystore file location and password are specified. Also a port for the https protocol is defined, which is different from the port for the http protocol:

<Connector protocol="org.apache.coyote.http11.Http11Protocol"
           port="8443" maxThreads="200" scheme="https"
           secure="true" SSLEnabled="true"
           keystoreFile="/usr/share/tomcat.keystore"
           keystorePass="my-password"
           clientAuth="false" sslProtocol="TLS"
           URIEncoding="UTF-8"
           compression="force"
           compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css"/>

So the full server configuration for the application looked liked this in the Tomcat server configuration file (/opt/tomcat/conf/server.xml):

<Service name="my-application">
  <Connector protocol="org.apache.coyote.http11.Http11Protocol"
             port="8443" maxThreads="200" scheme="https"
             secure="true" SSLEnabled="true"
             keystoreFile="/usr/share/tomcat.keystore"
             keystorePass="my-password"
             clientAuth="false" sslProtocol="TLS"
             URIEncoding="UTF-8"
             compression="force"
             compressableMimeType="text/html,text/xml,text/plain,text/javascript,text/css"/>

  <Connector port="8009" protocol="HTTP/1.1"
             connectionTimeout="20000"
             redirectPort="8443" />

  <Engine name="my-application" defaultHost="localhost">
     <Realm className="org.apache.catalina.realm.LockOutRealm">
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
             resourceName="UserDatabase"/>
    </Realm>

    <Host name="localhost"  appBase="webapps"
          unpackWARs="true" autoDeploy="true">

        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
             prefix="localhost_access_log" suffix=".txt"
             pattern="%h %l %u %t &quot;%r&quot; %s %b" />

    </Host>
  </Engine>
</Service>

This time when I tried accessing the application from the browser using:

https://my-server-ip-address:https-port

In my case it was:

https:35.123.45.6:8443

it worked fine. Although, I had to accept a warning which added a security exception for the website since the certificate used is a self-signed one.

That's all.

I hope this helps

Promise Preston
  • 24,334
  • 12
  • 145
  • 143
3

I solved this problem by replacing https to http

Arman
  • 111
  • 1
  • 4
2

I got this error resolved by doing 2 things in chrome browser:

  1. Pressed Ctrl + Shift + Delete and cleared all browsing data from beginning.
  2. Go to Chrome's : Settings ->Advanced Settings -> Open proxy settings -> Internet Properties then Go to the Content window and click on the Clear SSL State Button.

This site has this information and other options as well : https://www.thesslstore.com/blog/fix-err-ssl-protocol-error/

1

Answering this old question (for others which may help)

Configuring your httpd conf correctly will make the problem solved. Install any httpd server, if you don't have one.

Listing my config here.

[smilyface@box002 ~]$ cat /etc/httpd/conf/httpd.conf | grep shirts | grep -v "#"


        ProxyPass /shirts-service http://local.box002.com:16743/shirts-service
        ProxyPassReverse /shirts-service http://local.box002.com:16743/shirts-service
        ProxyPass /shirts http://local.box002.com:16443/shirts
        ProxyPassReverse /shirts http://local.box002.com:16443/shirts
        ...
        ...
        ...

edit the file as above and then restart httpd as below

[smilyface@box002 ~]$ sudo service httpd restart


And then request with with https will work without exception.
Also request with http will forward to https ! No worries.

smilyface
  • 5,021
  • 8
  • 41
  • 57
0

I was getting the same exception, whenever a page was getting loaded,

NFO: Error parsing HTTP request header
 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
java.lang.IllegalArgumentException: Invalid character found in method name. HTTP method names must be tokens
    at org.apache.coyote.http11.InternalInputBuffer.parseRequestLine(InternalInputBuffer.java:139)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1028)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    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)

I found that one of my page URL was https instead of http, when I changed the same, error was gone.

Pang
  • 9,564
  • 146
  • 81
  • 122
0

This usually happens when you are using a URI scheme that is not supported by the server in which the app is deployed. So, you might either want to check what all schemes your server supports and modify your request URI accordingly, or, you might want to add the support for that scheme in your server. The scope of your application should help you decide on this.

noob
  • 774
  • 1
  • 10
  • 23
0

It happened to me when I had a same port used in ssh tunnel SOCKS to run Proxy in 8080 port and my server and my firefox browser proxy was set to that port and got this issue.

privatejava
  • 703
  • 1
  • 9
  • 20
0

You can also try turning off the SSL option in settings, in case you are sending it through POSTMAN

Guru
  • 2,739
  • 1
  • 25
  • 27
0

I solved this problem by simply turning off my vpn.

Linyun Liu
  • 721
  • 6
  • 7
0

I was having this problem when I call any get/post Method in my api of webservices in spring. The problem is: parameter was not encoded. Use the java.net.URLEncoder to encode any parameter in your request: i.e. For the parameter called "id" I'm encoding the "idParameter" variable that I'll send in the request:

     String paramsForURL = "?id=" + URLEncoder.encode(idParameter, "UTF-8")