예제 #1
0
파일: main.c 프로젝트: Windeal/httpd
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 ;
}
예제 #2
0
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]);
}
예제 #3
0
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;
}
예제 #4
0
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;
}