void serve_file(int clientfd, const char* file_path) { Logger(LOG_INFO, 0, "serve file %s\n", file_path); FILE *resource; char buf[1024]; char filename[1024]; int numchars = 1; int file_len = 0; int status_code; strcpy(filename, FILE_DIR); strcat(filename, file_path); resource = fopen(filename, "r"); if (resource == NULL) { strcpy(filename, FILE_DIR); strcat(filename, "/notfound.html"); resource = fopen(filename, "r"); status_code = 404; } else { status_code = 200; } response_header(clientfd, resource, status_code); send_file(clientfd, resource); fclose(resource); return ; }
void post(char *uri, char *param, int header_count, char **headers) { int i; response_header(200, "OK", 0, NULL); printf("Request method: POST\r\n"); printf("Request URI: %s\r\n", uri); printf("Request parameters: %s\r\n", param); printf("Request headers: %d\r\n", header_count); for (i = 0; i < header_count; i++) printf("\t%s\r\n", headers[i]); }
void http_server(void) { char *ret; // HTTP methodを受け取る char method[METHOD_LEN + 1]; ret = read_until(method, METHOD_LEN + 1, " "); // methodが正しく送られてこなければ400エラーを返す if (ret == NULL || ret == &method[METHOD_LEN + 1]) { response_header(400, "Bad Request", 0, NULL); return; } // methodがGET,POSTでなければ501エラーを返す if (strcmp(method, "GET") != 0 && strcmp(method, "POST") != 0) { response_header(501, "Not Implemented", 0, NULL); return; } // URIを受け取る char uri[URI_LEN + 1]; ret = read_until(uri, URI_LEN + 1, " "); // URIが正しく送られてこなければ414エラーを返す if (ret == NULL || ret == &uri[URI_LEN + 1]) { response_header(414, "Request-URI Too Long", 0, NULL); return; } // HTTP versionを受け取る char version[VERSION_LEN + 2]; ret = read_until(version, VERSION_LEN + 2, "\r\n"); // HTTP versionが正しく送られてこなければ400エラーを返す if (ret == NULL || ret == &version[VERSION_LEN + 2]) { response_header(400, "Bad Request", 0, NULL); return; } // HTTP versionが1.1でなければ505エラーを返す if (strcmp(version, "HTTP/1.1") != 0) { response_header(505, "HTTP Version Not Supported", 0, NULL); return; } // URIに?が含まれていれば,パラメータを抽出 char *param = strchr(uri, '?'); if (param == NULL) param = &uri[strlen(uri)]; else *(param++) = '\0'; int status = 0, header_count = 0; char header[HEADER_LEN + 2], **headers = NULL; while (1) { // HTTP headerを受け取る ret = read_until(header, HEADER_LEN + 2, "\r\n"); // HTTP headerが正しく送られてこなければ400エラーを返す if (ret == NULL || ret == &header[HEADER_LEN + 2]) { status = 400; break; } // 長さが0であればヘッダーの終端 if (strlen(header) == 0) break; // ヘッダーに:が含まれていなければ400エラーを返す char *delimiter = strchr(header, ':'); if (delimiter == NULL) { status = 400; return; } // headersをreallocする char **ret_s = (char **)realloc(headers, sizeof(char *) * (header_count + 1)); if (ret_s == NULL) { perror("realloc() failed"); status = 500; break; } else { headers = ret_s; header_count++; } // headersの最後の要素にheaderをコピーするための領域を確保する ret = (char *)malloc(sizeof(char) * (strlen(header) + 1)); if (ret == NULL) { perror("realloc() failed"); status = 500; break; } else { headers[header_count - 1] = ret; } // headerをコピーする ret = strcpy(headers[header_count - 1], header); } // エラーがなければmethodに応じで関数を呼ぶ if (status == 0) { if (strcmp(method, "GET") == 0) get(uri, param, header_count, headers); else if (strcmp(method, "POST") == 0) post(uri, param, header_count, headers); } else if (status == 400) { response_header(400, "Bad Request", 0, NULL); } else if (status == 500) { response_header(500, "Internal Server Error", 0, NULL); } // 確保した領域を解放 int i = 0; for(i = 0; i < header_count; i++) free(headers[i]); free(headers); return; }
HIDDEN int ws_start_channel(struct transaction_t *txn, const char *protocol, int (*data_cb)(struct buf *inbuf, struct buf *outbuf, struct buf *logbuf, void **rock)) { int r; const char **hdr, *accept = NULL; wslay_event_context_ptr ev; struct ws_context *ctx; struct wslay_event_callbacks callbacks = { recv_cb, send_cb, NULL, NULL, NULL, NULL, on_msg_recv_cb }; /* Check for supported WebSocket version */ hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Version"); if (!hdr) { txn->error.desc = "Missing WebSocket version"; return HTTP_BAD_REQUEST; } else if (hdr[1]) { txn->error.desc = "Multiple WebSocket versions"; return HTTP_BAD_REQUEST; } else if (strcmp(hdr[0], WS_VERSION)) { txn->error.desc = "Unsupported WebSocket version"; return HTTP_UPGRADE; } if (protocol) { /* Check for supported WebSocket subprotocol */ int i, found = 0; hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Protocol"); if (!hdr) { txn->error.desc = "Missing WebSocket protocol"; return HTTP_BAD_REQUEST; } for (i = 0; !found && hdr[i]; i++) { tok_t tok = TOK_INITIALIZER(hdr[i], ",", TOK_TRIMLEFT|TOK_TRIMRIGHT); char *token; while ((token = tok_next(&tok))) { if (!strcmp(token, protocol)) { found = 1; break; } } tok_fini(&tok); } if (!found) { txn->error.desc = "Unsupported WebSocket protocol"; return HTTP_BAD_REQUEST; } } if (txn->flags.ver == VER_1_1) { unsigned char sha1buf[SHA1_DIGEST_LENGTH]; /* Check for WebSocket client key */ hdr = spool_getheader(txn->req_hdrs, "Sec-WebSocket-Key"); if (!hdr) { txn->error.desc = "Missing WebSocket client key"; return HTTP_BAD_REQUEST; } else if (hdr[1]) { txn->error.desc = "Multiple WebSocket client keys"; return HTTP_BAD_REQUEST; } else if (strlen(hdr[0]) != WS_CKEY_LEN) { txn->error.desc = "Invalid WebSocket client key"; return HTTP_BAD_REQUEST; } /* Create WebSocket accept key */ buf_setcstr(&txn->buf, hdr[0]); buf_appendcstr(&txn->buf, WS_GUID); xsha1((u_char *) buf_base(&txn->buf), buf_len(&txn->buf), sha1buf); buf_ensure(&txn->buf, WS_AKEY_LEN+1); accept = buf_base(&txn->buf); r = sasl_encode64((char *) sha1buf, SHA1_DIGEST_LENGTH, (char *) accept, WS_AKEY_LEN+1, NULL); if (r != SASL_OK) syslog(LOG_WARNING, "sasl_encode64: %d", r); } /* Create server context */ r = wslay_event_context_server_init(&ev, &callbacks, txn); if (r) { syslog(LOG_WARNING, "wslay_event_context_init: %s", wslay_strerror(r)); return HTTP_SERVER_ERROR; } /* Create channel context */ ctx = xzmalloc(sizeof(struct ws_context)); ctx->event = ev; ctx->accept = accept; ctx->protocol = protocol; ctx->data_cb = data_cb; txn->ws_ctx = ctx; /* Check for supported WebSocket extensions */ parse_extensions(txn); /* Prepare log buffer */ /* Add client data */ buf_printf(&ctx->log, "%s", txn->conn->clienthost); if (httpd_userid) buf_printf(&ctx->log, " as \"%s\"", httpd_userid); if ((hdr = spool_getheader(txn->req_hdrs, "User-Agent"))) { buf_printf(&ctx->log, " with \"%s\"", hdr[0]); if ((hdr = spool_getheader(txn->req_hdrs, "X-Client"))) buf_printf(&ctx->log, " by \"%s\"", hdr[0]); else if ((hdr = spool_getheader(txn->req_hdrs, "X-Requested-With"))) buf_printf(&ctx->log, " by \"%s\"", hdr[0]); } /* Add request-line */ buf_printf(&ctx->log, "; \"WebSocket/%s via %s\"", protocol ? protocol : "echo" , txn->req_line.ver); ctx->log_tail = buf_len(&ctx->log); /* Tell client that WebSocket negotiation has succeeded */ if (txn->conn->sess_ctx) { /* Treat WS data as chunked response */ txn->flags.te = TE_CHUNKED; response_header(HTTP_OK, txn); /* Force the response to the client immediately */ prot_flush(httpd_out); } else response_header(HTTP_SWITCH_PROT, txn); /* Set connection as non-blocking */ prot_NONBLOCK(txn->conn->pin); /* Don't do telemetry logging in prot layer */ prot_setlog(txn->conn->pin, PROT_NO_FD); prot_setlog(txn->conn->pout, PROT_NO_FD); return 0; }