static void get_info_refs(char *arg) { const char *service_name = get_parameter("service"); struct strbuf buf = STRBUF_INIT; hdr_nocache(); if (service_name) { const char *argv[] = {NULL /* service name */, "--stateless-rpc", "--advertise-refs", ".", NULL}; struct rpc_service *svc = select_service(service_name); strbuf_addf(&buf, "application/x-git-%s-advertisement", svc->name); hdr_str(content_type, buf.buf); end_headers(); packet_write(1, "# service=git-%s\n", svc->name); packet_flush(1); argv[0] = svc->name; run_service(argv); } else { select_getanyfile(); for_each_namespaced_ref(show_text_ref, &buf); send_strbuf("text/plain", &buf); } strbuf_release(&buf); }
static void send_strbuf(const char *type, struct strbuf *buf) { hdr_int(content_length, buf->len); hdr_str(content_type, type); end_headers(); write_or_die(1, buf->buf, buf->len); }
static void send_local_file(const char *the_type, const char *name) { const char *p = git_path("%s", name); size_t buf_alloc = 8192; char *buf = xmalloc(buf_alloc); int fd; struct stat sb; fd = open(p, O_RDONLY); if (fd < 0) not_found("Cannot open '%s': %s", p, strerror(errno)); if (fstat(fd, &sb) < 0) die_errno("Cannot stat '%s'", p); hdr_int(content_length, sb.st_size); hdr_str(content_type, the_type); hdr_date(last_modified, sb.st_mtime); end_headers(); for (;;) { ssize_t n = xread(fd, buf, buf_alloc); if (n < 0) die_errno("Cannot read '%s'", p); if (!n) break; write_or_die(1, buf, n); } close(fd); free(buf); }
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 ;-) */ }
void MiniWebServer::send_error_code(Client& client, int code) { #if DEBUG Serial << F("TWS:Returning "); Serial.println(code, DEC); #endif client << F("HTTP/1.1 "); client.print(code, DEC); client << F(" OK\r\n"); if (code != 200) { end_headers(client); } }
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 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 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; }
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 ;-) */ }
int fetch_file(int connfd, const char *filename) { int fd, fsize; struct stat fs; void *mblock; const char *mime_type, *suffix; int i; fd = open(filename, O_RDONLY); fstat(fd, &fs); fsize = fs.st_size; mblock = mmap(NULL, fsize, PROT_WRITE, MAP_PRIVATE, fd, 0); if (mblock == MAP_FAILED) { close(fd); send_error(connfd, 404); return 0; } suffix = filename; for (i = (int) strlen(filename) - 1; i >= 0; --i) { if (filename[i] == '.') { suffix = filename + i; break; } } if (strcasecmp(suffix, ".html") == 0 || strcasecmp(suffix, ".htm") == 0) { mime_type = "text/html"; } else if (strcasecmp(suffix, ".css") == 0) { mime_type = "text/css"; } else if (strcasecmp(suffix, ".js") == 0) { mime_type = "application/x-javascript"; } else if (strcasecmp(suffix, ".c") == 0 || strcasecmp(suffix, ".h") == 0) { mime_type = "text/plain"; } else { mime_type = "application/octet-stream"; } send_response(connfd, 200, NULL); send_header(connfd, "Content-Type", mime_type); send_header(connfd, "Content-Length", "%d", fsize); end_headers(connfd); rio_writen(connfd, mblock, fsize); munmap(mblock, fsize); return 1; }
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); } }
void send_error(int connfd, int code) { char *buf = (char *) malloc(MAXBUF); const char *message = lookup_resp(code)->resp_msg; send_response(connfd, code, message); send_header(connfd, "Content-Type", "text/html"); send_header(connfd, "Connection", "close"); end_headers(connfd); snprintf(buf, MAXBUF, "<head>\n" "<title>Error Response</title>\n" "</head>\n" "<body>\n" "<h1>Error Response</h1>\n" "<p>Error code %d.</p>\n" "<p>Message: %s.</p>\n" "</body>", code, message); rio_writen(connfd, buf, strlen(buf)); free(buf); }
static void service_rpc(char *service_name) { const char *argv[] = {NULL, "--stateless-rpc", ".", NULL}; struct rpc_service *svc = select_service(service_name); struct strbuf buf = STRBUF_INIT; strbuf_reset(&buf); strbuf_addf(&buf, "application/x-git-%s-request", svc->name); check_content_type(buf.buf); hdr_nocache(); strbuf_reset(&buf); strbuf_addf(&buf, "application/x-git-%s-result", svc->name); hdr_str(content_type, buf.buf); end_headers(); argv[0] = svc->name; run_service(argv); strbuf_release(&buf); }
void TinyWebServer::send_error_code(Client& client, int code) { #if DEBUG Serial << F("TWS:Returning "); Serial.println(code, DEC); #endif client << F("HTTP/1.1 "); client.print(code, DEC); if (code==200) client << F(" OK\r\n"); else if (code==400) client << F(" Bad Request\r\n"); else if (code==404) client << F(" Not Found\r\n"); else if (code==414) client << F(" Request URI Too Long\r\n"); else if (code==417) client << F(" Expectation Failed\r\n"); client << F("Connection: close\r\n"); client << F("Cache-Control: no-cache\r\n"); if (code != 200) { end_headers(client); } }
int list_directory(int connfd, const char *dirname) { char *buf; DIR *d; struct dirent *dir; struct stat fs; const char *item_fmt; const char *filename; char *fullname; int len1, len2, nwritten = 0; int ret; d = opendir(dirname); if (d) { buf = (char *) malloc(MAXBUF); /* TODO: escape or quote dirname / filename */ nwritten += snprintf(buf + nwritten, MAXBUF - nwritten, "<!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n" "<html>\n" "<title>Directory listing for %s</title>\n" "<body>\n" "<h2>Directory listing for %s</h2>\n" "<hr>\n" "<ul>\n", dirname + 1, dirname + 1); while ((dir = readdir(d)) != NULL) { filename = dir->d_name; if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) { continue; } else { len1 = strlen(dirname); len2 = strlen(filename); fullname = (char *) malloc(len1 + len2 + 1); strcpy(fullname, dirname); strcpy(fullname + len1, filename); fullname[len1 + len2] = 0; if (strcasecmp(filename, "index.html") == 0 || strcasecmp(filename, "index.htm") == 0) { ret = fetch_file(connfd, fullname); free(fullname); free(buf); closedir(d); return ret; } else { stat(fullname, &fs); if (S_ISDIR(fs.st_mode)) { item_fmt = "<li><a href=\"%s/\">%s/</a>\n"; } else { item_fmt = "<li><a href=\"%s\">%s</a>\n"; } nwritten += snprintf(buf + nwritten, MAXBUF - nwritten, item_fmt, filename, filename); } free(fullname); } } closedir(d); nwritten += snprintf(buf + nwritten, MAXBUF - nwritten, "</ul>\n" "<hr>\n" "</body>\n" "</html>\n"); send_response(connfd, 200, NULL); send_header(connfd, "Content-Type", "text/html"); send_header(connfd, "Content-Length", "%d", nwritten); end_headers(connfd); rio_writen(connfd, buf, nwritten); free(buf); return 1; } send_error(connfd, 404); return 0; }
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; }
int handle_request(int connfd) { char *buf = (char *) malloc(MAXLINE); char *method, *uri, *version; char *fullpath; int nread; struct stat fs; int is_dir; int error_code = 0, ret = 0; rio_t rio; rio_initb(&rio, connfd); nread = rio_readlineb(&rio, buf, MAXLINE - 1); if (nread == 0) { error_code = 400; goto fail; } else if (buf[nread - 1] != '\n') { error_code = 414; goto fail; } else { buf[nread - 1] = 0; if (nread >= 2 && buf[nread - 2] == '\r') { buf[nread - 2] = 0; } } method = buf; for (uri = method; *uri != 0; ++uri) { if (*uri == ' ') { *uri = 0; ++uri; break; } } for (version = uri; *version != 0; ++version) { if (*version == ' ') { *version = 0; ++version; break; } } if (*method == 0 || *uri == 0 || *version == 0) { /* missing some fields in http request header */ error_code = 400; goto fail; } if (strcmp(method, "GET") != 0) { /* only allow GET method */ error_code = 405; goto fail; } goto next; fail: free(buf); if (error_code > 0) { send_error(connfd, error_code); return 0; } next: /* translate path and dispatch HTTP request according to path */ uri = translate_path(uri); fullpath = (char *) malloc(strlen(uri) + 2); fullpath[0] = '.'; strcpy(fullpath + 1, uri); if (stat(fullpath, &fs) != 0) { send_error(connfd, 404); } else { is_dir = S_ISDIR(fs.st_mode); if (is_dir) { if (fullpath[(int) strlen(fullpath) - 1] != '/') { send_response(connfd, 301, NULL); send_header(connfd, "Location", "%s/", fullpath); end_headers(connfd); } else { ret = list_directory(connfd, fullpath); } } else { ret = fetch_file(connfd, fullpath); } } free(fullpath); free(buf); return ret; }