Example #1
0
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);
	}
}
Example #2
0
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);
}
Example #3
0
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;
}