static int bad_request(struct strbuf *hdr, const struct service_cmd *c) { const char *proto = getenv("SERVER_PROTOCOL"); if (proto && !strcmp(proto, "HTTP/1.1")) { http_status(hdr, 405, "Method Not Allowed"); hdr_str(hdr, "Allow", !strcmp(c->method, "GET") ? "GET, HEAD" : c->method); } else http_status(hdr, 400, "Bad Request"); hdr_nocache(hdr); end_headers(hdr); return 0; }
bool http_header::build_response(string& out) const { out.clear(); if (status_ > 0) { if (cgi_mode_) out.format("STATUS: %d\r\n", status_); else { out = "HTTP/1.1 "; out << status_ << " " << http_status(status_) << "\r\n"; time_t now = time(NULL); char buf[64]; date_format(buf, sizeof(buf), now); out << "Date: " << buf << "\r\n"; out << "Server: acl\r\n"; } } if (!cookies_.empty()) { std::list<HttpCookie*>::const_iterator it = cookies_.begin(); for (; it != cookies_.end(); ++it) { out.format_append("Set-Cookie: %s=%s", (*it)->getName(), (*it)->getValue()); const std::list<HTTP_PARAM*>& params = (*it)->getParams(); std::list<HTTP_PARAM*>::const_iterator cit = params.begin(); for (; cit != params.end(); ++ cit) { out.format_append("; %s=%s", (*cit)->name, (*cit)->value); } out << "\r\n"; } } // 添加分段响应字段 if (range_from_ >= 0 && range_to_ >= range_from_ && range_total_ > 0) out << "Content-Range: bytes=" << range_from_ << '-' << range_to_ << '/' << range_total_ << "\r\n"; // 如果是 gzip 压缩数据,当非 chunked 传输时,必须取消 Content-Length 字段, // 同时禁止保持长连接,即: Connection: close if (transfer_gzip_) { out << "Content-Encoding: gzip\r\n"; if (!chunked_transfer_ && keep_alive_) const_cast<http_header*>(this)->keep_alive_ = false; if (content_length_ > 0) const_cast<http_header*>(this)->content_length_ = -1; } build_common(out); out << "\r\n"; return true; }
static NORETURN void die_webcgi(const char *err, va_list params) { if (dead <= 1) { vreportf("fatal: ", err, params); http_status(500, "Internal Server Error"); hdr_nocache(); end_headers(); } exit(0); /* we successfully reported a failure ;-) */ }
bool connection_base::print_error(std::streambuf &buf, http_error const &http) const { std::ostream stream(&buf); stream << http_status(http.code()); stream << http_date(boost::posix_time::second_clock::universal_time()); stream << http_header::server(); stream << http_header::connection_close(); stream << http_header("Content-Type", "text/plain; charset=utf-8"); stream << http_constants<char>::endl; return true; }
static NORETURN void not_found(const char *err, ...) { va_list params; http_status(404, "Not Found"); hdr_nocache(); end_headers(); va_start(params, err); if (err && *err) vfprintf(stderr, err, params); va_end(params); exit(0); }
static NORETURN void forbidden(const char *err, ...) { va_list params; http_status(403, "Forbidden"); hdr_nocache(); end_headers(); va_start(params, err); if (err && *err) vfprintf(stderr, err, params); va_end(params); exit(0); }
static JSBool req_status(JSContext* cx, JSObject* obj, jsval idval, jsval* vp) { int status = http_status(cx, obj); if(status < 0) return JS_FALSE; if(INT_FITS_IN_JSVAL(status)) { JS_SET_RVAL(cx, vp, INT_TO_JSVAL(status)); return JS_TRUE; } else { JS_ReportError(cx, "Invalid HTTP status."); return JS_FALSE; } }
/** Process an incoming action request @returns non-zero on success, 0 on failure (errno set) **/ int http_action_request(HTTP *http,char *action) { if (gui_post_action(action)==-1) { http_status(http,HTTP_ACCEPTED); http_type(http,"text/plain"); http_format(http,"Goodbye"); http_send(http); http_close(http); shutdown_now(); return 1; } else return 0; }
static void parse_response( void ) { char res[] = "HTTP/1.1 200 OK\r\n" "Server: GitHub.com\r\n" "Date: Sat, 27 Jun 2015 04:10:06 GMT\r\n" "Content-Type: text/html; charset=utf-8\r\n" "Transfer-Encoding: chunked\r\n" "Status: 200 OK\r\n" "Content-Security-Policy: default-src *; script-src assets-cdn.github.com collector-cdn.github.com; object-src assets-cdn.github.com; style-src 'self' 'unsafe-inline' 'unsafe-eval' assets-cdn.github.com; img-src 'self' data: assets-cdn.github.com identicons.github.com www.google-analytics.com collector.githubapp.com *.githubusercontent.com *.gravatar.com *.wp.com; media-src 'none'; frame-src 'self' render.githubusercontent.com gist.github.com www.youtube.com player.vimeo.com checkout.paypal.com; font-src assets-cdn.github.com; connect-src 'self' live.github.com wss://live.github.com uploads.github.com status.github.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com\r\n" "Cache-Control: no-cache\r\n" "Vary: X-PJAX\r\n" "X-UA-Compatible: IE=Edge,chrome=1\r\n" "Set-Cookie: logged_in=no; domain=.github.com; path=/; expires=Wed, 27 Jun 2035 04:10:06 -0000; secure; HttpOnly\r\n" "X-Request-Id: 8ea8d359ded1d2d30094d38b2a4e73d3\r\n" "X-Runtime: 0.037659\r\n" "X-GitHub-Request-Id: 999DDDE5:0A3A:102882A:558E221D\r\n" "Strict-Transport-Security: max-age=31536000; includeSubdomains; preload\r\n" "X-Content-Type-Options: nosniff\r\n" "X-XSS-Protection: 1; mode=block\r\n" "X-Frame-Options: deny\r\n" "Vary: Accept-Encoding\r\n" "X-Served-By: 1868c9f28a71d80b2987f48dbd1824a0\r\n" "\r\n"; size_t len = sizeof( res ); uint64_t i = 0; int rc = 0; float start = 0, end = 0, elapsed = 0; uint16_t maxhdrlen = UINT16_MAX; http_t *r = http_alloc(20); start = (float)clock()/CLOCKS_PER_SEC; for( i = 0; i < NLOOP; i++ ){ rc = http_res_parse( r, res, len, maxhdrlen ); assert( rc == HTTP_SUCCESS ); assert( http_version(r) == HTTP_V11 ); assert( http_status(r) == HTTP_OK ); assert( r->nheader == 19 ); http_init( r ); } end = (float)clock()/CLOCKS_PER_SEC; elapsed = end - start; http_free( r ); printf("\tElapsed %f seconds.\n", elapsed ); printf("\t%0.9f -> %f req/sec.\n", elapsed / NLOOP, 1.00000 / ( elapsed / NLOOP ) ); }
static NORETURN void die_webcgi(const char *err, va_list params) { static int dead; if (!dead) { char buffer[1000]; dead = 1; vsnprintf(buffer, sizeof(buffer), err, params); fprintf(stderr, "fatal: %s\n", buffer); http_status(500, "Internal Server Error"); hdr_nocache(); end_headers(); } exit(0); /* we successfully reported a failure ;-) */ }
static void http_router(struct evhttp_request *r, void *which_server) { char *remote_host; ev_uint16_t remote_port; const char *uri = evhttp_request_get_uri(r); struct evhttp_connection *conn = evhttp_request_get_connection(r); evhttp_connection_get_peer(conn, &remote_host, &remote_port); hlog(LOG_DEBUG, "http %s [%s] request %s", (which_server == (void *)1) ? "status" : "upload", remote_host, uri); http_requests++; /* status server routing */ if (which_server == (void *)1) { if (strncmp(uri, "/status.json", 12) == 0) { http_status(r); return; } if (strncmp(uri, "/counterdata?", 13) == 0) { http_counterdata(r, uri); return; } http_route_static(r, uri); return; } /* position upload server routing */ if (which_server == (void *)2) { if (strncmp(uri, "/", 7) == 0) { http_upload_position(r, remote_host); return; } hlog(LOG_DEBUG, "http request on upload server for '%s': 404 not found", uri); evhttp_send_error(r, HTTP_NOTFOUND, "Not found"); return; } hlog(LOG_ERR, "http request on unknown server for '%s': 404 not found", uri); evhttp_send_error(r, HTTP_NOTFOUND, "Server not found"); return; }
static void check_content_type(const char *accepted_type) { const char *actual_type = getenv("CONTENT_TYPE"); if (!actual_type) actual_type = ""; if (strcmp(actual_type, accepted_type)) { http_status(415, "Unsupported Media Type"); hdr_nocache(); end_headers(); format_write(1, "Expected POST with Content-Type '%s'," " but received '%s' instead.\n", accepted_type, actual_type); exit(0); } }
bool connection_base::print_static_content( std::string const &content_type, std::string const &content, std::streambuf &buf) const { if (!ws_info_.empty()) { return false; } std::ostream stream(&buf); stream << http_status(200); stream << http_header::connection_close(); print_common_headers(content_type, buf); stream << "Content-Length: " << content.size() << http_constants<char>::endl; stream << http_constants<char>::endl; stream << content; return true; }
bool http_header::build_response(string& out) const { out.clear(); if (status_ > 0) { if (cgi_mode_) out.format("STATUS: %d\r\n", status_); else { out = "HTTP/1.1 "; out << status_ << " " << http_status(status_) << "\r\n"; time_t now = time(NULL); char buf[64]; date_format(buf, sizeof(buf), now); out << "Date: " << buf << "\r\n"; } } if (!cookies_.empty()) { std::list<HttpCookie*>::const_iterator it = cookies_.begin(); for (; it != cookies_.end(); ++it) { out.format_append("Set-Cookie: %s=%s", (*it)->getName(), (*it)->getValue()); const std::list<HTTP_PARAM*>& params = (*it)->getParams(); std::list<HTTP_PARAM*>::const_iterator cit = params.begin(); for (; cit != params.end(); ++ cit) { out.format_append("; %s=%s", (*cit)->name, (*cit)->value); } out << "\r\n"; } } build_common(out); out << "\r\n"; return true; }
static inline int parse_response( lua_State *L, lhttp_t *h, char *buf, size_t len ) { http_t *r = h->r; int rc = 0; luaL_checktype( L, 2, LUA_TTABLE ); luaL_checktype( L, 3, LUA_TTABLE ); rc = http_res_parse( r, buf, len, h->maxhdrlen ); if( rc == HTTP_SUCCESS ) { uint8_t i = 0; uint8_t nheader = r->nheader; uintptr_t key = 0; uint16_t klen = 0; uintptr_t val = 0; uint16_t vlen = 0; // export to table lua_settop( L, 3 ); // add to header table for(; i < nheader; i++ ){ http_getheader_at( r, &key, &klen, &val, &vlen, i ); lstate_strll2tbl( L, buf + key, klen, buf + val, vlen ); } lua_pop( L, 1 ); lstate_num2tbl( L, "version", http_version( r ) ); lstate_num2tbl( L, "status", http_status( r ) ); lstate_strl2tbl( L, "reason", buf + r->msg, r->msglen ); // initialize http_init( r ); } // add status lua_pushinteger( L, rc ); return 1; }
bool connection_base::print_headers(std::string const &content_type, std::streambuf &buf) const { bool is_websocket = !ws_info_.empty(); if (is_websocket && !ws_info_.valid()) { return false; } std::ostream stream(&buf); if (is_websocket) { ws_info_.write_headers(stream); } else { stream << http_status(200); stream << http_header::connection_close(); stream << http_header("Transfer-Encoding", "chunked"); } print_common_headers(content_type, buf); stream << http_constants<char>::endl; if (is_websocket) { ws_info_.write_body(stream); } return true; }
/** Process an incoming request @returns nothing **/ void http_response(SOCKET fd) { HTTP *http = http_create(fd); size_t len; int content_length = 0; char *user_agent = NULL; char *host = NULL; int keep_alive = 0; char *connection = NULL; char *accept = NULL; struct s_map { char *name; enum {INTEGER,STRING} type; void *value; size_t sz; } map[] = { {"Content-Length", INTEGER, (void*)&content_length, 0}, {"Host", STRING, (void*)&host, 0}, {"Keep-Alive", INTEGER, (void*)&keep_alive, 0}, {"Connection", STRING, (void*)&connection, 0}, {"Accept", STRING, (void*)&accept, 0}, }; while ( (int)(len=recv_data(fd,http->query,sizeof(http->query)))>0 ) { /* first term is always the request */ char *request = http->query; char method[32]; char uri[1024]; char version[32]; char *p = strchr(http->query,'\r'); int v; /* initialize the response */ http_reset(http); /* read the request string */ if (sscanf(request,"%s %s %s",method,uri,version)!=3) { http_status(http,HTTP_BADREQUEST); http_format(http,HTTP_BADREQUEST); http_type(http,"text/html"); http_send(http); break; } /* read the rest of the header */ while (p!=NULL && (p=strchr(p,'\r'))!=NULL) { *p = '\0'; p+=2; for ( v=0 ; v<sizeof(map)/sizeof(map[0]) ; v++ ) { if (map[v].sz==0) map[v].sz = strlen(map[v].name); if (strnicmp(map[v].name,p,map[v].sz)==0 && strncmp(p+map[v].sz,": ",2)==0) { if (map[v].type==INTEGER) { *(int*)(map[v].value) = atoi(p+map[v].sz+2); break; } else if (map[v].type==STRING) { *(char**)map[v].value = p+map[v].sz+2; break; } } } } output_verbose("%s (host='%s', len=%d)",http->query,host?host:"???",content_length); /* reject anything but a GET */ if (stricmp(method,"GET")!=0) { http_status(http,HTTP_METHODNOTALLOWED); http_format(http,HTTP_METHODNOTALLOWED); http_type(http,"text/html"); /* technically, we should add an Allow entry to the response header */ http_send(http); break; } /* handle request */ if ( strcmp(uri,"/favicon.ico")==0 ) { if ( http_favicon(http) ) http_status(http,HTTP_OK); else http_status(http,HTTP_NOTFOUND); http_send(http); } else { static struct s_map { char *path; int (*request)(HTTP*,char*); char *success; char *failure; } map[] = { /* this is the map of recognize request types */ {"/xml/", http_xml_request, HTTP_OK, HTTP_NOTFOUND}, {"/gui/", http_gui_request, HTTP_OK, HTTP_NOTFOUND}, {"/output/", http_output_request, HTTP_OK, HTTP_NOTFOUND}, {"/action/", http_action_request, HTTP_ACCEPTED,HTTP_NOTFOUND}, {"/rt/", http_get_rt, HTTP_OK, HTTP_NOTFOUND}, {"/perl/", http_run_perl, HTTP_OK, HTTP_NOTFOUND}, {"/gnuplot/", http_run_gnuplot, HTTP_OK, HTTP_NOTFOUND}, {"/java/", http_run_java, HTTP_OK, HTTP_NOTFOUND}, {"/python/", http_run_python, HTTP_OK, HTTP_NOTFOUND}, {"/r/", http_run_r, HTTP_OK, HTTP_NOTFOUND}, {"/scilab/", http_run_scilab, HTTP_OK, HTTP_NOTFOUND}, {"/octave/", http_run_octave, HTTP_OK, HTTP_NOTFOUND}, }; int n; for ( n=0 ; n<sizeof(map)/sizeof(map[0]) ; n++ ) { size_t len = strlen(map[n].path); if (strncmp(uri,map[n].path,len)==0) { if ( map[n].request(http,uri+len) ) http_status(http,map[n].success); else http_status(http,map[n].failure); http_send(http); goto Next; } } } /* deprecated XML usage */ if (strncmp(uri,"/",1)==0 ) { if ( http_xml_request(http,uri+1) ) { output_warning("deprecate XML usage in request '%s'", uri); http_status(http,HTTP_OK); } else http_status(http,HTTP_NOTFOUND); http_send(http); } else { http_status(http,HTTP_NOTFOUND); http_format(http,HTTP_NOTFOUND); http_type(http,"text/html"); http_send(http); } /* keep-alive not desired*/ Next: if (connection && stricmp(connection,"close")==0) break; } http_close(http); output_verbose("socket %d closed",http->s); }
int main(int argc, char **argv) { char *method = getenv("REQUEST_METHOD"); char *dir; struct service_cmd *cmd = NULL; char *cmd_arg = NULL; int i; git_setup_gettext(); git_extract_argv0_path(argv[0]); set_die_routine(die_webcgi); if (!method) die("No REQUEST_METHOD from server"); if (!strcmp(method, "HEAD")) method = "GET"; dir = getdir(); for (i = 0; i < ARRAY_SIZE(services); i++) { struct service_cmd *c = &services[i]; regex_t re; regmatch_t out[1]; if (regcomp(&re, c->pattern, REG_EXTENDED)) die("Bogus regex in service table: %s", c->pattern); if (!regexec(&re, dir, 1, out, 0)) { size_t n; if (strcmp(method, c->method)) { const char *proto = getenv("SERVER_PROTOCOL"); if (proto && !strcmp(proto, "HTTP/1.1")) { http_status(405, "Method Not Allowed"); hdr_str("Allow", !strcmp(c->method, "GET") ? "GET, HEAD" : c->method); } else http_status(400, "Bad Request"); hdr_nocache(); end_headers(); return 0; } cmd = c; n = out[0].rm_eo - out[0].rm_so; cmd_arg = xmemdupz(dir + out[0].rm_so + 1, n - 1); dir[out[0].rm_so] = 0; break; } regfree(&re); } if (!cmd) not_found("Request not supported: '%s'", dir); setup_path(); if (!enter_repo(dir, 0)) not_found("Not a git repository: '%s'", dir); if (!getenv("GIT_HTTP_EXPORT_ALL") && access("git-daemon-export-ok", F_OK) ) not_found("Repository not exported: '%s'", dir); git_config(http_config, NULL); cmd->imp(cmd_arg); return 0; }
void http_response(SOCKET fd) { HTTP *http = http_create(fd); size_t len; int content_length = 0; char *user_agent = NULL; char *host = NULL; int keep_alive = 0; char *connection = NULL; char *accept = NULL; struct s_map { char *name; enum {INTEGER,STRING} type; void *value; int sz; } map[] = { {"Content-Length", INTEGER, (void*)&content_length, 0}, {"Host", STRING, (void*)&host, 0}, {"Keep-Alive", INTEGER, (void*)&keep_alive, 0}, {"Connection", STRING, (void*)&connection, 0}, {"Accept", STRING, (void*)&accept, 0}, }; while ( (int)(len=recv_data(fd,http->query,sizeof(http->query)))>0 ) { /* first term is always the request */ char *request = http->query; char method[32]; char uri[1024]; char version[32]; char *p = strchr(http->query,'\r'); int v; /* read the request string */ if (sscanf(request,"%s %s %s",method,uri,version)!=3) { http_status(http,HTTP_BADREQUEST); http_format(http,HTTP_BADREQUEST); http_type(http,"text/html"); http_send(http); break; } /* read the rest of the header */ while (p!=NULL && (p=strchr(p,'\r'))!=NULL) { *p = '\0'; p+=2; for ( v=0 ; v<sizeof(map)/sizeof(map[0]) ; v++ ) { if (map[v].sz==0) map[v].sz = strlen(map[v].name); if (strnicmp(map[v].name,p,map[v].sz)==0 && strncmp(p+map[v].sz,": ",2)==0) { if (map[v].type==INTEGER) { *(int*)(map[v].value) = atoi(p+map[v].sz+2); break; } else if (map[v].type==STRING) { *(char**)map[v].value = p+map[v].sz+2; break; } } } } output_verbose("%s (host='%s', len=%d)",http->query,host?host:"???",content_length); /* reject anything but a GET */ if (stricmp(method,"GET")!=0) { http_status(http,HTTP_METHODNOTALLOWED); http_format(http,HTTP_METHODNOTALLOWED); http_type(http,"text/html"); /* technically, we should add an Allow entry to the response header */ http_send(http); break; } /* handle request */ if (strncmp(uri,"/gui/",5)==0 ) { if ( http_gui_request(http,uri+5) ) http_status(http,HTTP_OK); else http_status(http,HTTP_NOTFOUND); http_send(http); } else if (strncmp(uri,"/output/",8)==0 ) { if ( http_output_request(http,uri+8) ) http_status(http,HTTP_OK); else http_status(http,HTTP_NOTFOUND); http_send(http); } else if (strncmp(uri,"/action/",8)==0) { if ( http_action_request(http,uri+8) ) http_status(http,HTTP_ACCEPTED); else http_status(http,HTTP_NOTFOUND); http_send(http); } else if ( strcmp(uri,"/favicon.ico")==0 ) { if ( http_favicon(http) ) http_status(http,HTTP_OK); else http_status(http,HTTP_NOTFOUND); http_send(http); } else if (strncmp(uri,"/",1)==0 ) { if ( http_xml_request(http,uri+1) ) http_status(http,HTTP_OK); else http_status(http,HTTP_NOTFOUND); http_send(http); } else { http_status(http,HTTP_NOTFOUND); http_format(http,HTTP_NOTFOUND); http_type(http,"text/html"); http_send(http); } /* keep-alive not desired*/ if (connection && stricmp(connection,"close")==0) break; } http_close(http); output_verbose("socket %d closed",http->s); }