Error parsing HTTP request header--400 bad request

问题描述:

JSP中通过form post方式请求URL传入json格式参数报错:

信息: 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 the request target. The valid characters are defined in RFC 7230 and RFC 3986
 at org.apache.coyote.http11.InternalAprInputBuffer.parseRequestLine(InternalAprInputBuffer.java:235)
 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.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2549)
 at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2538)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Thread.java:745)


var data =
 {
    "ids": [
        "0654B61D-5946-4875-A801-392DBEAB55F0"
    ],
    "docId": "6E846CE4-A818-443A-9A0A-28017084609A"
};



 这是我的请求:.../dataCenter/addEditDoc.do?command=fileDownload&data=JSON.stringify(data);



问题原因:

查资料了解到最新的tomcat6 7 8 都有这个问题,这个问题是由于tomcat的新版本增加了一个新特性,就是严格按照 RFC 3986规范进行访问解析,
 而 RFC 3986规范定义了Url中
 只允许包含英文字母(a-zA-Z)、数字(0-9)、-_.~4个特殊字符以及所有保留字符(RFC3986中指定了以下字符为保留字符:! * ’ ( ) ; : @ & = + $ , / ? # [ ])。




解决方法:

对json字符串中大括号进行URL编码,结果为:
 /dataCenter/addEditDoc.do?command=fileDownload&data="+JSON.stringify(data).replace('{','%7B').replace('}','%7D');
 



PS: ASCII字符与URL编码的对照表:
 
 ASCII字符   URL编码 
空格     %20 
!     %21 
"    %22 
#   %23 
$    %24 
%   %25 
&    %26 
'     %27 
(    %28 
)    %29 
*    %2A 
+   %2B 
,     %2C 
-     %2D 
.     %2E 
/    %2F 
0    %30 
1    %31 
2    %32 
3    %33 
4    %34 
5    %35 
6    %36 
7    %37 
8    %38 
9    %39 
:     %3A 
;     %3B 
<   %3C
=   %3D
>   %3E 
?    %3F 
@   %40 
A    %41 
B    %42 
C    %43 
D    %44 
E    %45 
F    %46 
G    %47 
H    %48 
I    %49 
J    %4A 
K    %4B 
L    %4C 
M   %4D 
N    %4E 
O   %4F 
P    %50 
Q   %51 
R    %52 
S    %53 
T    %54 
U    %55 
V    %56 
W   %57 
X    %58 
Y    %59 
Z    %5A 
[    %5B 
\    %5C 
]    %5D 
^   %5E 
_    %5F 
`    %60 
a    %61 
b    %62 
c    %63 
d    %64 
e    %65 
f     %66 
g    %67 
h    %68 
i     %69 
j     %6A 
k    %6B 
l     %6C 
m   %6D 
n    %6E 
o    %6F 
p    %70 
q    %71 
r     %72 
s    %73 
t     %74 
u    %75 
v    %76 
w   %77 
x    %78 
y    %79 
z    %7A 
{    %7B 
|    %7C 
}    %7D 
~   %7E 
%7F 
€    %80 
%81 
‚    %82 
ƒ    %83 
„    %84 
…   %85 
†    %86 
‡    %87 
ˆ    %88 
‰  %89 
Š    %8A 
‹     %8B 
Œ   %8C 
%8D 
Ž    %8E 
%8F 
%90 
‘   %91 
’   %92 
“   %93 
”   %94 
•    %95 
–    %96 
—  %97 
˜    %98 
™   %99 
š    %9A 
›     %9B 
œ   %9C 
%9D 
ž    %9E 
Ÿ    %9F 
%A0 
¡     %A1 
¢    %A2 
£    %A3 
%A4 
¥    %A5 
|    %A6 
§    %A7 
¨    %A8 
©   %A9 
ª    %AA 
«    %AB 
¬   %AC 
¯    %AD 
®   %AE 
¯    %AF 
°    %B0 
±   %B1 
²    %B2 
³    %B3 
´     %B4 
µ    %B5 
¶    %B6 
·     %B7 
¸     %B8 
¹    %B9 
º    %BA 
»    %BB 
¼   %BC 
½   %BD 
¾   %BE 
¿    %BF 
À    %C0 
Á    %C1 
    %C2 
à   %C3 
Ä    %C4 
Å    %C5 
Æ   %C6 
Ç    %C7 
È    %C8 
É    %C9 
Ê    %CA 
Ë    %CB 
Ì    %CC 
Í    %CD 
Π   %CE 
Ï    %CF 
Р  %D0 
Ñ    %D1 
Ò   %D2 
Ó   %D3 
Ô   %D4 
Õ   %D5 
Ö   %D6 
%D7 
Ø   %D8 
Ù    %D9 
Ú    %DA 
Û    %DB 
Ü    %DC 
Ý    %DD 
Þ    %DE 
ß    %DF 
à    %E0 
á    %E1 
â    %E2 
ã    %E3 
ä    %E4 
å    %E5 
æ   %E6 
ç    %E7 
è    %E8 
é    %E9 
ê    %EA 
ë    %EB 
ì     %EC 
í     %ED 
î     %EE 
ï     %EF 
ð    %F0 
ñ    %F1 
ò    %F2 
ó    %F3 
ô    %F4 
õ    %F5 
ö    %F6 
÷   %F7 
ø    %F8 
ù    %F9 
ú    %FA 
û    %FB 
ü    %FC 
ý    %FD 
þ    %FE 




















请为我修改为标准的C语言注释、代码中大括号上下要对齐// // webserver.c — Minimal multithreaded HTTP static file server (Linux) // Build: gcc webserver.c -o webserver -lpthread // Run: ./webserver // Browse: http://localhost:8080/ // // Serves files under the WEB_ROOT directory. Defaults to "Index.html". // Supports keep-alive on GET, basic content-type mapping, and zero-copy sendfile. // #include <arpa/inet.h> #include <fcntl.h> #include <netinet/in.h> #include <pthread.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/sendfile.h> #include <sys/socket.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #define PORT 8080 #define BUFFER_SIZE 8192 #define WEB_ROOT "web/" // ------------------------------- // Request structure & parsing // ------------------------------- typedef struct { char method[16]; char path[1024]; } Request; static Request parse_request(const char *buffer) { Request req; memset(&req, 0, sizeof(req)); strcpy(req.method, ""); // default empty strcpy(req.path, "/"); // default root // Very simple parse: METHOD PATH HTTP/1.1 // e.g., "GET /index.html HTTP/1.1" sscanf(buffer, "%15s %1023s", req.method, req.path); return req; } // ------------------------------- // Utilities // ------------------------------- static const char *guess_content_type(const char *path) { // crude extension check const char *ext = strrchr(path, '.'); if (!ext) return "text/html"; if (!strcmp(ext, ".html") || !strcmp(ext, ".htm")) return "text/html; charset=utf-8"; if (!strcmp(ext, ".css")) return "text/css; charset=utf-8"; if (!strcmp(ext, ".js")) return "application/javascript; charset=utf-8"; if (!strcmp(ext, ".json")) return "application/json; charset=utf-8"; if (!strcmp(ext, ".png")) return "image/png"; if (!strcmp(ext, ".jpg") || !strcmp(ext, ".jpeg")) return "image/jpeg"; if (!strcmp(ext, ".gif")) return "image/gif"; if (!strcmp(ext, ".svg")) return "image/svg+xml"; if (!strcmp(ext, ".ico")) return "image/x-icon"; if (!strcmp(ext, ".txt")) return "text/plain; charset=utf-8"; return "application/octet-stream"; } static bool contains_dotdot(const char *p) { return strstr(p, "..") != NULL; } // ------------------------------- // Client handler // ------------------------------- static void *handle_client(void *arg) { int client_fd = *((int *)arg); free(arg); int keep_alive = 1; // default keep-alive unless "Connection: close" char buffer[BUFFER_SIZE]; while (keep_alive) { memset(buffer, 0, sizeof(buffer)); ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer) - 1); if (bytes_read <= 0) break; // closed or error // Basic keep-alive check if (strstr(buffer, "Connection: close")) { keep_alive = 0; } Request req = parse_request(buffer); // Only support GET/HEAD for static content; POST placeholder if (!strcmp(req.method, "GET") || !strcmp(req.method, "HEAD")) { char full_path[2048]; struct stat st; // Directory traversal guard if (contains_dotdot(req.path)) { const char *bad = "HTTP/1.1 400 Bad Request\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Connection: close\r\n\r\n" "Bad Request"; write(client_fd, bad, strlen(bad)); break; } if (!strcmp(req.path, "/")) { snprintf(full_path, sizeof(full_path), "%sIndex.html", WEB_ROOT); } else { // strip leading '/' for local file path const char *sub = req.path[0] == '/' ? req.path + 1 : req.path; snprintf(full_path, sizeof(full_path), "%s%s", WEB_ROOT, sub); } if (stat(full_path, &st) < 0 || S_ISDIR(st.st_mode)) { const char *not_found = "HTTP/1.1 404 Not Found\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Connection: keep-alive\r\n\r\n" "<!doctype html><html><body><h1>404 Not Found</h1></body></html>"; write(client_fd, not_found, strlen(not_found)); continue; } else { const char *content_type = guess_content_type(full_path); // Headers char headers[512]; int n = snprintf(headers, sizeof(headers), "HTTP/1.1 200 OK\r\n" "Connection: keep-alive\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n\r\n", content_type, (long)st.st_size); write(client_fd, headers, (size_t)n); if (!strcmp(req.method, "HEAD")) { continue; // header only } int file_fd = open(full_path, O_RDONLY); if (file_fd != -1) { off_t offset = 0; size_t remaining = (size_t)st.st_size; while (remaining > 0) { ssize_t sent = sendfile(client_fd, file_fd, &offset, remaining); if (sent <= 0) break; remaining -= (size_t)sent; } close(file_fd); } } } else if (!strcmp(req.method, "POST")) { // Placeholder: echo 204 No Content (not implemented) char* contentLengthstr = strstr(buffer,"Content-Length"); if(!contentLengthstr) { printf("No content-length key\n"); } else { int contentLength; sscanf(contentLengthstr+14,":%d",&contentLength); char*payload = strstr(buffer, "\r\n\r\n"); for(int i=0;i<contentLength;i++) printf("%c",*(payload+4+i)); printf("\n"); } const char *resp = "HTTP/1.1 204 No Content\r\n" "Connection: keep-alive\r\n\r\n"; write(client_fd, resp, strlen(resp)); } else { const char *method_not_allowed = "HTTP/1.1 405 Method Not Allowed\r\n" "Allow: GET, HEAD, POST\r\n" "Connection: keep-alive\r\n\r\n"; write(client_fd, method_not_allowed, strlen(method_not_allowed)); } // Optional: break if the client sent only one request without keep-alive // (Most modern browsers default to keep-alive; we keep the loop.) } close(client_fd); return NULL; } // ------------------------------- // Main entry // ------------------------------- int main(void) { int server_fd; struct sockaddr_in address; int opt = 1; // Create socket if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("socket failed"); exit(EXIT_FAILURE); } // SO_REUSEADDR if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); close(server_fd); exit(EXIT_FAILURE); } // Bind memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) { perror("bind failed"); close(server_fd); exit(EXIT_FAILURE); } // Listen if (listen(server_fd, 10) < 0) { perror("listen"); close(server_fd); exit(EXIT_FAILURE); } printf("WebServer running on port %d\n", PORT); printf("Access at: http://localhost:%d/\n", PORT); // Accept loop while (1) { int *client_fd = (int *)malloc(sizeof(int)); if (!client_fd) { perror("malloc"); continue; } struct sockaddr_in client_addr; socklen_t addr_len = sizeof(client_addr); *client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len); if (*client_fd < 0) { perror("accept"); free(client_fd); continue; } // Client info (optional) char client_ip[INET_ADDRSTRLEN]; inet_ntop(AF_INET, &(client_addr.sin_addr), client_ip, INET_ADDRSTRLEN); // printf("New connection from: %s:%d\n", client_ip, ntohs(client_addr.sin_port)); pthread_t thread_id; if (pthread_create(&thread_id, NULL, handle_client, client_fd) != 0) { perror("pthread_create"); close(*client_fd); free(client_fd); continue; } pthread_detach(thread_id); // resources auto-released when thread exits } // Not reached close(server_fd); return 0; }
08-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值