static void on_write(uv_write_t* req, int status) { http_response* response = (http_response*) req->data; if (status != 0) { fprintf(stderr, "Write error: %s: %s\n", uv_err_name(status), uv_strerror(status)); destroy_response(response, 1); return; } if (response->response_offset >= response->response_size) { destroy_response(response, !response->request->keep_alive); return; } int r = uv_fs_read(loop, &response->read_req, response->fd, &response->buf, 1, response->response_offset, on_fs_read); if (r) { fprintf(stderr, "File read error: %s: %s\n", uv_err_name(r), uv_strerror(r)); response_error(response->handle, 500, "Internal Server Error", NULL); destroy_request(response->request, 1); } }
static void on_fs_read(uv_fs_t *req) { http_response* response = (http_response*) req->data; int result = req->result; uv_fs_req_cleanup(req); if (result < 0) { fprintf(stderr, "File read error: %s: %s\n", uv_err_name(result), uv_strerror(result)); response_error(response->handle, 500, "Internal Server Error", NULL); destroy_response(response, 1); return; } else if (result == 0) { destroy_response(response, 1); return; } uv_buf_t buf = uv_buf_init(response->pbuf, result); int r = uv_write(&response->write_req, (uv_stream_t*) response->handle, &buf, 1, on_write); if (r) { destroy_response(response, 1); return; } response->response_offset += result; }
static void on_fs_open(uv_fs_t* req) { http_request* request = (http_request*) req->data; int result = req->result; uv_fs_req_cleanup(req); free(req); if (result < 0) { fprintf(stderr, "Open error: %s: %s\n", uv_err_name(result), uv_strerror(result)); response_error(request->handle, 404, "Not Found\n", NULL); destroy_request(request, 1); return; } uv_fs_t stat_req; int r = uv_fs_fstat(loop, &stat_req, result, NULL); if (r) { fprintf(stderr, "Stat error: %s: %s\n", uv_err_name(r), uv_strerror(r)); response_error(request->handle, 404, "Not Found\n", NULL); destroy_request(request, 1); return; } uint64_t response_size = stat_req.statbuf.st_size; uv_fs_req_cleanup(&stat_req); const static char* ctype = "application/octet-stream"; const char* dot = request->file_path; const char* ptr = dot; while (dot) { ptr = dot; dot = strchr(dot + 1, '.'); } khint_t k = kh_get(mime_type, mime_type, ptr); if (k != kh_end(mime_type)) { ctype = kh_value(mime_type, k); } http_response* response = calloc(1, sizeof(http_response)); if (response == NULL) { fprintf(stderr, "Allocate error: %s\n", strerror(r)); response_error(request->handle, 404, "Not Found\n", NULL); destroy_request(request, 1); return; } response->response_size = response_size; response->fd = result; response->request = request; response->handle = request->handle; response->pbuf = malloc(WRITE_BUF_SIZE); if (response->pbuf == NULL) { fprintf(stderr, "Allocate error: %s\n", strerror(r)); response_error(request->handle, 404, "Not Found\n", NULL); destroy_response(response, 1); return; } response->buf = uv_buf_init(response->pbuf, WRITE_BUF_SIZE); response->read_req.data = response; response->write_req.data = response; char bufline[1024]; int nbuf = snprintf(bufline, sizeof(bufline), "HTTP/1.1 200 OK\r\n" "Content-Length: %" PRId64 "\r\n" "Content-Type: %s\r\n" "Connection: %s\r\n" "\r\n", response_size, ctype, (request->keep_alive ? "keep-alive" : "close")); uv_buf_t buf = uv_buf_init(bufline, nbuf); #ifndef _WIN32 r = uv_try_write((uv_stream_t*) request->handle, &buf, 1); if (r == 0) { fprintf(stderr, "Write error\n"); destroy_response(response, 1); return; } #else r = uv_write(&response->write_req, (uv_stream_t*) request->handle, &buf, 1, NULL); if (r) { fprintf(stderr, "Write error: %s: %s\n", uv_err_name(r), uv_strerror(r)); destroy_response(response, 1); return; } #endif r = uv_fs_read(loop, &response->read_req, result, &response->buf, 1, -1, on_fs_read); if (r) { response_error(request->handle, 500, "Internal Server Error\n", NULL); destroy_response(response, 1); } }
int main(int argc, char *argv[]) { int port = 1220; if (argc > 1) port = atoi(argv[1]); int fd = socket(AF_INET, SOCK_STREAM, 0); int flags = 1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&flags, sizeof(flags)); setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags)); struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); addr.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind()"); if(fd > 0) close(fd); exit(1); } if (listen(fd, 1024) < 0) { perror("listen()"); exit(1); } RespRequest *req = create_request(BUF_SIZE); RespResponse *res = create_response(BUF_SIZE); while (1) { reset_request(req); reset_response(res); socklen_t addr_len = sizeof(addr); int cfd = accept(fd, (struct sockaddr*)&addr, &addr_len); if (cfd < 0) { perror("accept()"); continue; } char buf[1024]; int rnum = read(cfd,buf,sizeof(buf)); if (decode_request(req, buf, rnum) == 0 && (req->state == OK || req->state == PART_OK) ){ if (req->argc > 1 && strncmp(request_argv(req,0), "add", 3) == 0) { int total = 0; for (int i = 1; i < req->argc; i++) total += atoi(request_argv(req,i)); encode_response_integer(res, total); } else { encode_response_status(res,0,"ERR unknown command"); } } else { encode_response_status(res,0,"ERR decode command fail"); } write(cfd, res->buf, res->used_size); close(cfd); } destroy_request(req); destroy_response(res); close(fd); return 0; }