void http_read(TCP_NODE * n, char *p_cmd, char *p_url, char *p_proto, HASH * p_head) { int code = 0; char lastmodified[DATE_SIZE]; char resource[BUF_SIZE]; char filename[BUF_SIZE]; char range[BUF_SIZE]; char *p_range = range; size_t filesize = 0; size_t content_length = 0; char keepalive[BUF_SIZE]; const char *mimetype = NULL; /* Get protocol */ if (!http_proto(n, p_proto)) { node_status(n, NODE_SHUTDOWN); goto END; } /* Get action */ if (!http_action(n, p_cmd)) { node_status(n, NODE_SHUTDOWN); goto END; } /* Get resource */ if (!http_resource(n, p_url, resource)) { node_status(n, NODE_SHUTDOWN); goto END; } /* Check Keep-Alive */ n->keepalive = http_keepalive(p_head, keepalive); /* Compute filename */ if (!http_filename(resource, filename)) { http_404(n, keepalive); info(_log, &n->c_addr, "404 %s", resource); goto END; } /* Compute file size */ filesize = http_size_simple(filename); /* Compute mime type */ mimetype = mime_find(filename); /* Last-Modified. */ if (!http_resource_modified(filename, p_head, lastmodified)) { http_304(n, keepalive); info(_log, &n->c_addr, "304 %s", resource); goto END; } /* Range request? */ if (http_range_detected(p_head, range)) { code = 206; } else { code = 200; } /* Normal 200-er request */ if (code == 200) { info(_log, &n->c_addr, "200 %s", resource); http_200(n, lastmodified, filename, filesize, keepalive, mimetype); http_body(n, filename, filesize); goto END; } /* Check for 'bytes=' in range. Fallback to 200 if necessary. */ if (!http_range_prepare(&p_range)) { info(_log, &n->c_addr, "200 %s", resource); http_200(n, lastmodified, filename, filesize, keepalive, mimetype); http_body(n, filename, filesize); goto END; } /* multipart/byteranges */ if (!http_range_multipart(p_range)) { RESPONSE *r_head = NULL, *r_file = NULL; /* Header */ if ((r_head = resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) { node_status(n, NODE_SHUTDOWN); goto END; } /* File */ if ((r_file = resp_put(n->response, RESPONSE_FROM_FILE)) == NULL) { node_status(n, NODE_SHUTDOWN); goto END; } /* Parse range. */ if (!http_range_simple(n, r_file, filename, filesize, p_range, &content_length)) { node_status(n, NODE_SHUTDOWN); goto END; } /* Header with known content_length */ http_206_simple(n, r_head, r_file, lastmodified, filename, filesize, content_length, keepalive, mimetype); info(_log, &n->c_addr, "206 %s [%s]", resource, range); goto END; } else { RESPONSE *r_head = NULL, *r_bottom = NULL, *r_zsyncbug = NULL; char boundary[12]; /* Create boundary string */ http_random(boundary, 12); /* Header */ if ((r_head = resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) { node_status(n, NODE_SHUTDOWN); goto END; } /* zsync bug? One more \r\n between header and body. */ if ((r_zsyncbug = resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) { node_status(n, NODE_SHUTDOWN); goto END; } /* Parse range. */ if (!http_range_complex (n, filename, filesize, mimetype, p_range, &content_length, boundary)) { node_status(n, NODE_SHUTDOWN); goto END; } /* Bottom */ if ((r_bottom = resp_put(n->response, RESPONSE_FROM_MEMORY)) == NULL) { node_status(n, NODE_SHUTDOWN); goto END; } http_206_boundary_finish(r_bottom, &content_length, boundary); /* Header with known content_length */ http_206_complex(n, r_head, lastmodified, filename, filesize, content_length, boundary, keepalive); /* zsync bug? One more \r\n between header and body. */ http_newline(r_zsyncbug, &content_length); info(_log, &n->c_addr, "206 %s [%s]", resource, range); goto END; } info(_log, &n->c_addr, "FIXME: HTTP parser end reached without result"); node_status(n, NODE_SHUTDOWN); END: /* HTTP Pipeline: There is at least one more request to parse. * Recursive request! Limited by the input buffer. */ if (n->pipeline != NODE_SHUTDOWN && n->recv_size > 0) { http_buf(n); } }
static void processor(const char *tx_addr, int port) { sys_init(1); sys_log('E', "started port=%d, tx=%s\n", port, tx_addr); /* connect to the control thread */ char addr[MAX_ADDR]; sys_address(addr, port); IO *io = sys_connect(addr, IO_CHUNK); tx_attach(tx_addr); /* get env code from the tx */ char *code = tx_program(); char *res = mem_alloc(MAX_BLOCK); while (!io->stop) { sys_iready(io, -1); int status = -1; long long sid = 0LL, time = sys_millis(); Env *env = NULL; Arg *arg = NULL; Vars *v = vars_new(0), *r = NULL, *w = NULL; Http_Req *req = http_parse_req(io); if (io->stop) goto exit; if (req == NULL) { status = http_400(io); goto exit; } if (req->method == OPTIONS) { status = http_opts(io); goto exit; } env = env_new("net", code); if (str_idx(req->path, "/fn") == 0) { int idx = (req->path[3] == '/') ? 4 : 3; int i = 0, len = 1, cnt = 0; Func **fns = env_funcs(env, req->path + idx, &cnt); status = http_200(io); while (status == 200 && len) { len = pack_fn2csv(fns, cnt, res, MAX_BLOCK, &i); status = http_chunk(io, res, len); } mem_free(fns); goto exit; } /* compare the request with the function defintion */ Func *fn = env_func(env, req->path + 1); if (fn == NULL) { Error *err = error_new("unknown function '%s'", req->path + 1); status = http_404(io, err->msg); mem_free(err); goto exit; } if (fn->rp.name != NULL && req->method != POST) { status = http_405(io, POST); goto exit; } if (fn->rp.name == NULL && req->method == POST) { status = http_405(io, GET); goto exit; } /* TODO: think what to do with duplicate parameter values */ for (int i = 0; i < req->args->len; ++i) { char *name = req->args->names[i]; if (array_freq(req->args->names, req->args->len, name) > 1) { Error *err = error_new("duplicate parameter '%s' " "(not supported)", name); status = http_404(io, err->msg); mem_free(err); goto exit; } } if (fn->pp.len != req->args->len) { Error *err = error_new("expected %d primitive parameters, got %d", fn->pp.len, req->args->len); status = http_404(io, err->msg); mem_free(err); goto exit; } arg = mem_alloc(sizeof(Arg)); for (int i = 0; i < fn->pp.len; ++i) { char *name = fn->pp.names[i]; Type t = fn->pp.types[i]; int idx = array_scan(req->args->names, req->args->len, name); if (idx < 0) { Error *err = error_new("unknown parameter '%s'", name); status = http_404(io, err->msg); mem_free(err); goto exit; } char *val = req->args->vals[idx]; int error = 0; if (t == Int) { arg->vals[i].v_int = str_int(val, &error); } else if (t == Real) arg->vals[i].v_real = str_real(val, &error); else if (t == Long) arg->vals[i].v_long = str_long(val, &error); else if (t == String) { error = str_len(val) > MAX_STRING; if (!error) str_cpy(arg->vals[i].v_str, val); } if (error) { Error *err = error_new("value '%s' (parameter '%s') " "is not of type '%s'", val, name, type_to_str(t)); status = http_404(io, err->msg); mem_free(err); goto exit; } } if (fn->rp.name != NULL) { TBuf *body = NULL; if (req->len > 0) { Error *err = pack_csv2rel(req->body, fn->rp.head, &body); if (err != NULL) { status = http_404(io, err->msg); mem_free(err); goto exit; } } else { body = tbuf_new(); } vars_add(v, fn->rp.name, 0, body); /* project the parameter */ Rel *param = rel_project(rel_load(fn->rp.head, fn->rp.name), fn->rp.head->names, fn->rp.head->len); rel_eval(param, v, arg); /* clean the previous version */ tbuf_clean(body); tbuf_free(body); /* replace with the new body */ int vpos = array_scan(v->names, v->len, fn->rp.name); v->vals[vpos] = param->body; param->body = NULL; rel_free(param); } /* start a transaction */ r = vars_new(fn->r.len); w = vars_new(fn->w.len); for (int i = 0; i < fn->r.len; ++i) vars_add(r, fn->r.names[i], 0, NULL); for (int i = 0; i < fn->w.len; ++i) vars_add(w, fn->w.names[i], 0, NULL); sid = tx_enter(addr, r, w); /* prepare variables */ for (int i = 0; i < r->len; ++i) { TBuf *body = vol_read(r->vols[i], r->names[i], r->vers[i]); vars_add(v, r->names[i], 0, body); } for (int i = 0; i < w->len; ++i) { int pos = array_scan(v->names, v->len, w->names[i]); if (pos < 0) vars_add(v, w->names[i], 0, NULL); } for (int i = 0; i < fn->t.len; ++i) vars_add(v, fn->t.names[i], 0, NULL); /* evaluate the function body */ for (int i = 0; i < fn->slen; ++i) rel_eval(fn->stmts[i], v, arg); /* prepare the return value. note, the resulting relation is just a container for the body, so it is not freed */ Rel *ret = NULL; if (fn->ret != NULL) ret = fn->stmts[fn->slen - 1]; /* persist the global variables */ for (int i = 0; i < w->len; ++i) { int idx = array_scan(v->names, v->len, w->names[i]); if (idx < 0) { status = http_500(io); goto exit; } vol_write(w->vols[i], v->vals[idx], w->names[i], w->vers[i]); tbuf_free(v->vals[idx]); v->vals[idx] = NULL; } /* confirm a success and send the result back */ status = http_200(io); if (status != 200) goto exit; tx_commit(sid); /* N.B. there is no explicit revert as the transaction manager handles nested tx_enter and a connectivity failure as a rollback */ int len = 1, i = 0; while (status == 200 && len) { len = pack_rel2csv(ret, res, MAX_BLOCK, i++); status = http_chunk(io, res, len); } exit: if (status != -1) sys_log('E', "%016llX method %c, path %s, time %lldms - %3d\n", sid, (req == NULL) ? '?' : req->method, (req == NULL) ? "malformed" : req->path, sys_millis() - time, status); if (r != NULL) vars_free(r); if (w != NULL) vars_free(w); if (arg != NULL) mem_free(arg); if (req != NULL) http_free_req(req); if (env != NULL) env_free(env); for (int i = 0; i < v->len; ++i) if (v->vals[i] != NULL) { tbuf_clean(v->vals[i]); tbuf_free(v->vals[i]); } vars_free(v); sys_term(io); } mem_free(code); mem_free(res); tx_detach(); sys_close(io); }
int main() { std::cout<< "http server \n" "\nlog: \n\n" "type | file \n" "-------------------------\n"; WSADATA wsa; assert( WSAStartup( MAKEWORD( 2, 2 ), &wsa ) == 0 ); addrinfo *res = NULL; addrinfo hints; ZeroMemory( &hints, sizeof( hints ) ); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; hints.ai_flags = AI_PASSIVE; assert( getaddrinfo( NULL, "80", &hints, &res ) == 0 ); SOCKET s = socket( res->ai_family, res->ai_socktype, res->ai_protocol ); assert( s != INVALID_SOCKET ); assert( bind( s, res->ai_addr, (int)res->ai_addrlen ) != SOCKET_ERROR ); assert( listen( s, SOMAXCONN ) != SOCKET_ERROR ); /* Main server loop */ std::string method =""; char buffer[512]; int bytes; std::string strBuffer=""; std::string filename=""; std::string output=""; while(1){ SOCKET client = accept( s, NULL, NULL ); assert( client != INVALID_SOCKET ); /* Read user request into the buffer */ bytes = recv( client, buffer, 512, 0 ); method = http_operation_type(buffer); if (method == "GET" || method == "POST" || method== "HEAD"){ /* supported methods */ std::cout <<method; strBuffer=buffer; /* User wants to receive some file, let's find out which one. */ filename = http_get_requested_file(buffer); std::cout <<" " <<filename; if (method != "HEAD"){ output = read_file(WWW_DIR + filename); /* Prepare response, if length of file is 0, file wasn't found */ if (output.length() < 1){ output = http_404(); }else{ /* Else, send response with file content and headers */ output = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" + http_file_extension_to_content_type( filename ) + "\r\n" + output; } }else{ output = "HTTP/1.1 200 OK\r\n" "Connection: close\r\n" + http_file_extension_to_content_type( filename ) + "\r\n"; } assert( send( client, output.c_str(), output.length(), 0 ) > 0 ); std::cout <<" \n"; } else{ std::cout <<"Unknown method: " <<method <<"'\n"; send( client, http_404(), strlen(http_404()), 0 ); } assert( shutdown( client, SD_BOTH ) != SOCKET_ERROR ); closesocket( client ); //WSACleanup(); } system("pause"); return 0; }