http.c
字号:
/* Populate HTTP envelope data with higher-level CONNECT information if one present. */ if (ssl_host) { ret->host = ssl_host; ret->port = ssl_port; ret->from_ssl = 1; } if (!ret->host[0]) http_error(client,"Host name is missing",1); ret->host = strdup(ret->host); if (!ret->host) fatal("out of memory"); /* Grab query data */ if (!ret->is_connect && (x = strchr(ret->path,'?'))) { *(x++) = 0; ret->query = strdup(x); if (!ret->query) fatal("out of memory"); } /* Grab path data */ if (!ret->is_connect) { ret->path = strdup(ret->path); if (!ret->path) fatal("out of memory"); x = strrchr(ret->path,'.'); if (x) ret->ext = x + 1; } /* Request target is now fully parsed. Let's collect headers, if any. */ while (1) { line = grab_line(client); if (!line) http_error(client,"Incomplete or malformed request headers",1); /* Empty line == end of headers */ if (!line[0]) break; x = strchr(line,':'); if (!x) http_error(client,"Invalid request header",1); *x = 0; while (isspace(*(++x))); if (!strcasecmp(line,"Content-Length")) { ret->payload_len = atoi(x); if (ret->payload_len > MAXPAYLOAD) http_error(client,"Payload size limit exceeded",1); } if (!strncasecmp(line,"Cookie",6)) parse_cookies(x,&ret->cookies); if (!strcasecmp(line,"Referer")) { _u8* rh; ret->referer = strdup(x); if (!ret->referer) fatal("out of memory"); /* Extract referer host to simplify other checks later on. */ if ((rh = strstr(x,"://"))) { _u8* x; rh = strdup(rh + 3); if (!rh) fatal("out of memory"); if ((x = strchr(rh,'/'))) *x = 0; if ((x = strchr(rh,':'))) *x = 0; ret->ref_host = rh; } } if (!strcasecmp(line,"X-Ratproxy-Loop")) http_error(client,"Proxy loop detected",1); /* These are specific to publicly documented anti-XSRF features of Google Web Toolkit and Google Data APIs; this might be further extended to accomodate other custom schemes in popular frameworks. */ if (!strcasecmp(line,"Authorization") && !strncasecmp(x,"GoogleLogin auth=",17)) { ret->xsrf_safe = 1; ret->authsub = 1; } if (!strcasecmp(line,"Content-Type")) { if (rp_strcasestr(x,"text/x-gwt-rpc")) { ret->xsrf_safe = 1; ret->authsub = 1; } if (rp_strcasestr(x,"multipart/form-data")) ret->multipart = 1; else if (!rp_strcasestr(x,"application/x-www-form-urlencoded")) ret->non_param = 1; } DYN_ADD2(ret->h,line,x); } /* Get POST payload */ if (ret->payload_len) { ret->payload = malloc(ret->payload_len + 1); if (!ret->payload) fatal("out of memory"); if (fread(ret->payload,ret->payload_len,1,client) != 1) http_error(client,"Premature end of payload data",0); /* To make string matching safe. */ ret->payload[ret->payload_len] = 0; } /* Parse GET/POST parameters */ if (ret->query) parse_urlencoded(&ret->p, ret->query); ret->ppar_bound = ret->p.c; /* Do not parse payloads of arcane types. */ if (ret->payload && !ret->non_param) { if (ret->multipart) parse_multipart(&ret->p, ret->payload, ret->payload_len); else parse_urlencoded(&ret->p, ret->payload); } /* Locate XSRF tokens, if any */ /* Do not perform contains_token() checks on file fields. */ for (i=0;i<ret->p.c;i++) if (!ret->p.fn[i][0] && contains_token(ret->p.v1[i],ret->p.v2[i])) { ret->xsrf_safe = 1; break; } return ret;}/* Connect to server */static FILE* open_server(FILE* client, _u8* host, _u32 port) { FILE* ret; struct sockaddr_in sin; struct hostent* he; _s32 ss; if (!(he = gethostbyname(host)) || !(he->h_addr_list[0])) http_error(client,"Unable to find target host",0); ss = socket(PF_INET, SOCK_STREAM, 0); if (ss < 0) pfatal("socket() failed"); sin.sin_family = PF_INET; sin.sin_port = htons(port); memcpy(&sin.sin_addr, he->h_addr_list[0], 4); if (connect(ss,(struct sockaddr*)&sin,sizeof(struct sockaddr_in))) http_error(client,"Connection to target failed",0); ret = fdopen(ss,"w+"); if (!ret) fatal("fdopen() failed"); setvbuf(ret, srv_buf, _IOFBF, sizeof(srv_buf)); return ret;}/* Connect to server, take proxy CONNECT handling into account */FILE* open_server_complete(FILE* client, struct http_request* r) { FILE* ret; _u8* l; if (use_proxy) ret = open_server(client, use_proxy, proxy_port); else ret = open_server(client, r->host, r->port); if (r->is_connect) { if (use_proxy) { fprintf(ret,"CONNECT %s:%u HTTP/1.0\r\n\r\n",r->host,r->port); fflush(ret); setvbuf(ret, srv_buf, _IONBF, 0); /* Sink proxy response */ while ((l=grab_line(ret)) && l[0]); } if (client) { fprintf(client,"HTTP/1.0 200 Go ahead, please.\r\n\r\n"); fflush(client); } } return ret;}#define NEEDS_URLENC(x) \ (!(x) || !strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.",toupper(x)))/* Rewrite GET and POST parameters as needed. */void reconstruct_request(struct http_request* r) { struct dyn_str p = { 0, 0 }, q = { 0, 0 }; _u32 cp = 0, i; _u8 c; _u8 tmp[32]; /* Encode params to query string, until ppar boundary is hit. */ for (;cp<r->p.c;cp++) { if (cp == r->ppar_bound) break; if (q.l) STR_APPEND_CHAR(q,'&'); i = 0; while ((c=r->p.v1[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(q,tmp); i++; } STR_APPEND_CHAR(q,'='); i = 0; while ((c=r->p.v2[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(q,tmp); i++; } } /* Update query string. */ if (q.l) r->query = q.v; /* Deal with the rest of parameters, putting them in a multipart envelope or as urlencoded payload, as needed. */ if (r->multipart) { /* Update boundary; be just random enough to prevent accidents. */ sprintf(tmp,"ratproxybound%08x",rand()); r->use_boundary = strdup(tmp); if (!r->use_boundary) fatal("out of memory"); for (;cp<r->p.c;cp++) { STR_APPEND(p,"--"); STR_APPEND(p,r->use_boundary); STR_APPEND(p,"\r\nContent-Disposition: form-data; name=\""); STR_APPEND(p,r->p.v1[cp]); if (r->p.fn[cp][0]) { STR_APPEND(p,"\"; filename=\""); STR_APPEND(p,r->p.fn[cp]); } STR_APPEND(p,"\"\r\n\r\n"); if (r->p.l2[cp]) { STR_APPEND_RAWMEM(p,r->p.v2[cp],r->p.l2[cp]); } else { STR_APPEND(p,r->p.v2[cp]); } STR_APPEND(p,"\r\n"); } STR_APPEND(p,"--"); STR_APPEND(p,r->use_boundary); STR_APPEND(p,"--\r\n"); } else if (!r->non_param) { for (;cp<r->p.c;cp++) { if (p.l) STR_APPEND_CHAR(p,'&'); i = 0; while ((c=r->p.v1[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(p,tmp); i++; } STR_APPEND_CHAR(p,'='); i = 0; while ((c=r->p.v2[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(p,tmp); i++; } } if (p.l) STR_APPEND(p,"\r\n"); } else return; /* Leave payload intact. */ /* Update POST string. */ if (p.l) { r->payload = p.v; r->payload_len = p.l; } return;}/* Detect and convert GWT RPC syntax where appropriate. This is specific to Google Web Toolkit. */static _u8* maybe_gwt_rpc(_u8* str) { struct dyn_str p = { 0, 0 }; _u8 *c = str, *n; _u32 num = 0; _u32 l = strlen(str); if (l < 3 || str[l-3] != 0xEF || str[l-2] != 0xBF || str[l-1] != 0xBF) return str; STR_APPEND(p,"GWT_RPC["); while ((n = strstr(c,"\xEF\xBF\xBF"))) { *n = 0; if (num > 4) { if (num != 5) STR_APPEND_CHAR(p,','); STR_APPEND_CHAR(p,'\''); if (!strncmp(c,"[L",2)) c += 2; if (!strncmp(c,"com.google.",11) || !strncmp(c,"java.",5)) c = strrchr(c,'.') + 1; /* We *could* escape here, but it's probably not worth the effort. */ STR_APPEND(p,c); STR_APPEND_CHAR(p,'\''); } num++; *n = '\xEF'; c = n + 3; } STR_APPEND_CHAR(p,']'); return p.v;}/* Convert multipart data to URLencoded string, to simplify reporting. */_u8* stringify_payload(struct http_request* r) { struct dyn_str p = { 0, 0 }; _u32 cp, i, c; _u8 tmp[32]; if (!r->multipart) return maybe_gwt_rpc(r->payload); /* Reconstruct payload from multipart boundary... */ for (cp=r->ppar_bound;cp<r->p.c;cp++) { if (p.l) STR_APPEND_CHAR(p,'&'); i = 0; while ((c=r->p.v1[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(p,tmp); i++; } STR_APPEND_CHAR(p,'='); /* When dealing with a file field, use field name, rather than field data. */ if (r->p.fn[cp][0]) { STR_APPEND(p,"FILE["); i = 0; while ((c=r->p.fn[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(p,tmp); i++; } STR_APPEND_CHAR(p,']'); } else { i = 0; while ((c=r->p.v2[cp][i])) { if (NEEDS_URLENC(c)) { sprintf(tmp,"%%%02X",c); } else { tmp[0] = c; tmp[1] = 0; } STR_APPEND(p,tmp); i++; } } } return p.v;}/* Do a naive date comparison for t-1 sec/min/hr scenarios. */_u8 comp_dates(_u8* exp, _u8* dat) { _s32 i = strlen(dat), dc = 0; if (i != strlen(exp)) return 1; while (--i >= 0) { if (exp[i] != dat[i]) { if (!isdigit(dat[i]) || exp[i] > dat[i] || ++dc > 1) return 1; } } return 0;}/* Send HTTP request, collect and parse response, spot header-related problems. */struct http_response* send_request(FILE* client, FILE* server, struct http_request* r, _u8 strip_state) { struct http_response* ret; _u8 *line, *x; _s32 decl_clen = -1; _u32 i; _u8 port_spec[16] = { 0 }; _u8 *exp_value = 0, *dat_value = 0; /* Send the request... unfortunately, we cannot specify :80 on all standard requests, as some URL rewriters that redirect to https will copy this over and cause problems. */ if (!r->from_ssl) { if (r->port != 80) sprintf(port_spec,":%u",r->port); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -