Add proxy example (draft)
This commit is contained in:
@@ -2,3 +2,5 @@ simple_client
|
|||||||
simple_client.exe
|
simple_client.exe
|
||||||
simple_server
|
simple_server
|
||||||
simple_server.exe
|
simple_server.exe
|
||||||
|
proxy
|
||||||
|
proxy.exe
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ endif
|
|||||||
|
|
||||||
.PHONY: all clean example
|
.PHONY: all clean example
|
||||||
|
|
||||||
all: chttp.c chttp.h simple_client$(EXT) simple_server$(EXT)
|
all: chttp.c chttp.h simple_client$(EXT) simple_server$(EXT) proxy$(EXT)
|
||||||
|
|
||||||
chttp.c chttp.h: $(wildcard src/*.c src/*.h) misc/amalg.py Makefile
|
chttp.c chttp.h: $(wildcard src/*.c src/*.h) misc/amalg.py Makefile
|
||||||
python misc/amalg.py
|
python misc/amalg.py
|
||||||
@@ -26,4 +26,4 @@ chttp.c chttp.h: $(wildcard src/*.c src/*.h) misc/amalg.py Makefile
|
|||||||
gcc $< chttp.c -o $@ $(CFLAGS) $(LFLAGS)
|
gcc $< chttp.c -o $@ $(CFLAGS) $(LFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm chttp.c chttp.h simple_client simple_client.exe simple_server simple_server.exe
|
rm chttp.c chttp.h simple_client simple_client.exe simple_server simple_server.exe proxy proxy.exe
|
||||||
|
|||||||
@@ -1199,12 +1199,11 @@ static int parse_response(Scanner *s, HTTP_Response *res)
|
|||||||
|| !is_digit(s->src[s->cur+2])
|
|| !is_digit(s->src[s->cur+2])
|
||||||
|| s->src[s->cur+3] != ' ')
|
|| s->src[s->cur+3] != ' ')
|
||||||
return -1;
|
return -1;
|
||||||
s->cur += 5;
|
|
||||||
|
|
||||||
res->status =
|
res->status =
|
||||||
(s->src[s->cur-2] - '0') * 1 +
|
(s->src[s->cur+0] - '0') * 100 +
|
||||||
(s->src[s->cur-3] - '0') * 10 +
|
(s->src[s->cur+1] - '0') * 10 +
|
||||||
(s->src[s->cur-4] - '0') * 100;
|
(s->src[s->cur+2] - '0') * 1;
|
||||||
|
s->cur += 4;
|
||||||
|
|
||||||
// Parse reason phrase: HTAB / SP / VCHAR / obs-text
|
// Parse reason phrase: HTAB / SP / VCHAR / obs-text
|
||||||
// Note: obs-text (obsolete text, octets 0x80-0xFF) is not validated
|
// Note: obs-text (obsolete text, octets 0x80-0xFF) is not validated
|
||||||
@@ -2708,16 +2707,16 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
|
|||||||
|
|
||||||
int socket_manager_translate_events(
|
int socket_manager_translate_events(
|
||||||
SocketManager *sm, SocketEvent *events,
|
SocketManager *sm, SocketEvent *events,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
int num_events = 0;
|
int num_events = 0;
|
||||||
for (int i = 0; i < reg->num_polled; i++) {
|
for (int i = 0; i < reg.num_polled; i++) {
|
||||||
|
|
||||||
if (!reg->polled[i].revents)
|
if (!reg.polled[i].revents)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (reg->polled[i].fd == sm->plain_sock ||
|
if (reg.polled[i].fd == sm->plain_sock ||
|
||||||
reg->polled[i].fd == sm->secure_sock) {
|
reg.polled[i].fd == sm->secure_sock) {
|
||||||
|
|
||||||
// We only listen for input events from the listener
|
// We only listen for input events from the listener
|
||||||
// if the socket pool isn't fool. This ensures that
|
// if the socket pool isn't fool. This ensures that
|
||||||
@@ -2733,7 +2732,7 @@ int socket_manager_translate_events(
|
|||||||
|
|
||||||
// Determine whether the event came from
|
// Determine whether the event came from
|
||||||
// the encrypted listener or not.
|
// the encrypted listener or not.
|
||||||
bool secure = (reg->polled[i].fd == sm->secure_sock);
|
bool secure = (reg.polled[i].fd == sm->secure_sock);
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->state != SOCKET_STATE_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
@@ -2741,7 +2740,7 @@ int socket_manager_translate_events(
|
|||||||
assert(s - sm->sockets < + sm->max_used);
|
assert(s - sm->sockets < + sm->max_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
NATIVE_SOCKET sock = accept(reg->polled[i].fd, NULL, NULL);
|
NATIVE_SOCKET sock = accept(reg.polled[i].fd, NULL, NULL);
|
||||||
if (sock == NATIVE_SOCKET_INVALID)
|
if (sock == NATIVE_SOCKET_INVALID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -2774,7 +2773,7 @@ int socket_manager_translate_events(
|
|||||||
|
|
||||||
sm->num_used++;
|
sm->num_used++;
|
||||||
|
|
||||||
} else if (reg->polled[i].fd == sm->wait_sock) {
|
} else if (reg.polled[i].fd == sm->wait_sock) {
|
||||||
|
|
||||||
// Consume one byte from the wakeup signal
|
// Consume one byte from the wakeup signal
|
||||||
char byte;
|
char byte;
|
||||||
@@ -2785,9 +2784,7 @@ int socket_manager_translate_events(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
Socket *s = reg.ptrs[i];
|
||||||
Socket *s = reg->ptrs[i];
|
|
||||||
if (reg->polled[i].revents)
|
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3850,6 +3847,12 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
if (conn->state != HTTP_CLIENT_CONN_WAIT_URL)
|
if (conn->state != HTTP_CLIENT_CONN_WAIT_URL)
|
||||||
return; // Request line already written
|
return; // Request line already written
|
||||||
|
|
||||||
|
if (url.len == 0) {
|
||||||
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a copy of the URL string so the parsed
|
// Allocate a copy of the URL string so the parsed
|
||||||
// URL pointers remain valid
|
// URL pointers remain valid
|
||||||
char *url_copy = malloc(url.len);
|
char *url_copy = malloc(url.len);
|
||||||
@@ -4124,14 +4127,11 @@ void http_client_register_events(HTTP_Client *client,
|
|||||||
socket_manager_register_events(&client->sockets, reg);
|
socket_manager_register_events(&client->sockets, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_process_events(HTTP_Client *client,
|
void http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
||||||
int ret = socket_manager_translate_events(&client->sockets, events, reg);
|
int num_events = socket_manager_translate_events(&client->sockets, events, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
int num_events = ret;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -4253,8 +4253,6 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
client->num_ready++;
|
client->num_ready++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
@@ -4311,7 +4309,7 @@ void http_free_response(HTTP_Response *response)
|
|||||||
#define POLL poll
|
#define POLL poll
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int http_client_wait_response(HTTP_Client *client,
|
void http_client_wait_response(HTTP_Client *client,
|
||||||
int *result, void **user, HTTP_Response **response)
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -4325,15 +4323,11 @@ int http_client_wait_response(HTTP_Client *client,
|
|||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
int ret = http_client_process_events(client, ®);
|
http_client_process_events(client, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (http_client_next_response(client, result, user, response))
|
if (http_client_next_response(client, result, user, response))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -4558,14 +4552,11 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_process_events(HTTP_Server *server,
|
void http_server_process_events(HTTP_Server *server,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_SERVER_CAPACITY];
|
SocketEvent events[HTTP_SERVER_CAPACITY];
|
||||||
int ret = socket_manager_translate_events(&server->sockets, events, reg);
|
int num_events = socket_manager_translate_events(&server->sockets, events, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
int num_events = ret;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -4606,8 +4597,6 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
http_server_conn_process_events(server, conn);
|
http_server_conn_process_events(server, conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
@@ -4626,7 +4615,7 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_wait_request(HTTP_Server *server,
|
void http_server_wait_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -4639,15 +4628,11 @@ int http_server_wait_request(HTTP_Server *server,
|
|||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
int ret = http_server_process_events(server, ®);
|
http_server_process_events(server, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (http_server_next_request(server, request, builder))
|
if (http_server_next_request(server, request, builder))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a connection pointer from a response builder.
|
// Get a connection pointer from a response builder.
|
||||||
@@ -4836,7 +4821,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str)
|
|||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER) {
|
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) {
|
||||||
append_special_headers(conn);
|
append_special_headers(conn);
|
||||||
conn->state = HTTP_SERVER_CONN_WAIT_BODY;
|
conn->state = HTTP_SERVER_CONN_WAIT_BODY;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -619,7 +619,7 @@ void socket_manager_register_events(SocketManager *sm,
|
|||||||
// socket structs provided to the socket manager
|
// socket structs provided to the socket manager
|
||||||
// via the init function.
|
// via the init function.
|
||||||
int socket_manager_translate_events(SocketManager *sm,
|
int socket_manager_translate_events(SocketManager *sm,
|
||||||
SocketEvent *events, EventRegister *reg);
|
SocketEvent *events, EventRegister reg);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CONNECT_TARGET_NAME,
|
CONNECT_TARGET_NAME,
|
||||||
@@ -1037,8 +1037,8 @@ void http_client_register_events(HTTP_Client *client,
|
|||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
// I/O events to be triggered, so now the HTTP client
|
// I/O events to be triggered, so now the HTTP client
|
||||||
// can continue its buffering and flushing operations.
|
// can continue its buffering and flushing operations.
|
||||||
int http_client_process_events(HTTP_Client *client,
|
void http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg);
|
EventRegister reg);
|
||||||
|
|
||||||
// After some I/O events were processes, some responses
|
// After some I/O events were processes, some responses
|
||||||
// may be availabe. This function returns one of the
|
// may be availabe. This function returns one of the
|
||||||
@@ -1051,7 +1051,7 @@ bool http_client_next_response(HTTP_Client *client,
|
|||||||
int *result, void **user, HTTP_Response **response);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_client_wait_response(HTTP_Client *client,
|
void http_client_wait_response(HTTP_Client *client,
|
||||||
int *result, void **user, HTTP_Response **response);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// Free a response object. You can't access its fields
|
// Free a response object. You can't access its fields
|
||||||
@@ -1248,8 +1248,8 @@ void http_server_register_events(HTTP_Server *server,
|
|||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
// I/O events to be triggered, so now the HTTP server
|
// I/O events to be triggered, so now the HTTP server
|
||||||
// can continue its buffering and flushing operations.
|
// can continue its buffering and flushing operations.
|
||||||
int http_server_process_events(HTTP_Server *server,
|
void http_server_process_events(HTTP_Server *server,
|
||||||
EventRegister *reg);
|
EventRegister reg);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HTTP_Server *server;
|
HTTP_Server *server;
|
||||||
@@ -1269,7 +1269,7 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_server_wait_request(HTTP_Server *server,
|
void http_server_wait_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// This function is called to set the status code of
|
// This function is called to set the status code of
|
||||||
|
|||||||
@@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <winsock2.h>
|
||||||
|
#define POLL WSAPoll
|
||||||
|
#else
|
||||||
|
#include <poll.h>
|
||||||
|
#define POLL poll
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../chttp.h"
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
HTTP_String remote = HTTP_STR("http://coz.is");
|
||||||
|
|
||||||
|
HTTP_Client client;
|
||||||
|
ret = http_client_init(&client);
|
||||||
|
if (ret < 0) {
|
||||||
|
printf("Couldn't initialize client (%s)\n", http_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_Server server;
|
||||||
|
ret = http_server_init(&server);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't initialize server (%s)\n", http_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
http_server_set_reuse_addr(&server, true);
|
||||||
|
http_server_set_trace_bytes(&server, true);
|
||||||
|
|
||||||
|
ret = http_server_listen_tcp(&server, HTTP_STR("127.0.0.1"), 8080);
|
||||||
|
if (ret < 0) {
|
||||||
|
fprintf(stderr, "Couldn't start listening (%s)\n", http_strerror(ret));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool used[HTTP_SERVER_CAPACITY];
|
||||||
|
for (int i = 0; i < HTTP_SERVER_CAPACITY; i++)
|
||||||
|
used[i] = false;
|
||||||
|
|
||||||
|
HTTP_ResponseBuilder pending[HTTP_SERVER_CAPACITY];
|
||||||
|
int num_pending = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
#define POLL_CAPACITY (HTTP_CLIENT_POLL_CAPACITY + HTTP_SERVER_POLL_CAPACITY)
|
||||||
|
|
||||||
|
void *ptrs[POLL_CAPACITY];
|
||||||
|
struct pollfd polled[POLL_CAPACITY];
|
||||||
|
|
||||||
|
EventRegister server_reg = {
|
||||||
|
ptrs,
|
||||||
|
polled,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
http_server_register_events(&server, &server_reg);
|
||||||
|
|
||||||
|
EventRegister client_reg = {
|
||||||
|
ptrs + server_reg.num_polled,
|
||||||
|
polled + server_reg.num_polled,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
http_client_register_events(&client, &client_reg);
|
||||||
|
|
||||||
|
if (server_reg.num_polled > 0 ||
|
||||||
|
client_reg.num_polled > 0) {
|
||||||
|
int num_polled = server_reg.num_polled
|
||||||
|
+ client_reg.num_polled;
|
||||||
|
POLL(polled, num_polled, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int result;
|
||||||
|
void *user;
|
||||||
|
HTTP_Response *response;
|
||||||
|
http_client_process_events(&client, client_reg);
|
||||||
|
while (http_client_next_response(&client, &result, &user, &response)) {
|
||||||
|
|
||||||
|
HTTP_ResponseBuilder *builder = (HTTP_ResponseBuilder*) user;
|
||||||
|
|
||||||
|
int i = builder - pending;
|
||||||
|
assert(i > -1);
|
||||||
|
assert(i < HTTP_SERVER_CAPACITY);
|
||||||
|
|
||||||
|
if (result == HTTP_OK) {
|
||||||
|
http_response_builder_status(*builder, response->status);
|
||||||
|
http_response_builder_body(*builder, response->body);
|
||||||
|
http_response_builder_send(*builder);
|
||||||
|
} else {
|
||||||
|
http_response_builder_status(*builder, 500);
|
||||||
|
http_response_builder_send(*builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
used[i] = false;
|
||||||
|
num_pending--;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_Request *request;
|
||||||
|
HTTP_ResponseBuilder response_builder;
|
||||||
|
http_server_process_events(&server, server_reg);
|
||||||
|
while (http_server_next_request(&server, &request, &response_builder)) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (used[i]) {
|
||||||
|
i++;
|
||||||
|
assert(i < HTTP_SERVER_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_String path = request->url.path;
|
||||||
|
if (path.len == 0)
|
||||||
|
path = HTTP_STR("/");
|
||||||
|
|
||||||
|
char target[1<<10];
|
||||||
|
int target_len = snprintf(target, sizeof(target),
|
||||||
|
"%.*s%.*s", HTTP_UNPACK(remote), HTTP_UNPACK(path));
|
||||||
|
if (target_len < 0 || target_len >= (int) sizeof(target)) {
|
||||||
|
http_response_builder_status(response_builder, 500);
|
||||||
|
http_response_builder_send(response_builder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTP_RequestBuilder request_builder = http_client_get_builder(&client);
|
||||||
|
http_request_builder_set_user(request_builder, &pending[i]);
|
||||||
|
http_request_builder_trace(request_builder, true);
|
||||||
|
http_request_builder_method(request_builder, request->method);
|
||||||
|
http_request_builder_target(request_builder, (HTTP_String) { target, target_len });
|
||||||
|
ret = http_request_builder_send(request_builder);
|
||||||
|
if (ret < 0) {
|
||||||
|
http_response_builder_status(response_builder, 500);
|
||||||
|
http_response_builder_send(response_builder);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
used[i] = true;
|
||||||
|
pending[i] = response_builder;
|
||||||
|
num_pending++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http_server_free(&server);
|
||||||
|
http_client_free(&client);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -26,11 +26,7 @@ int main(void)
|
|||||||
int result;
|
int result;
|
||||||
void *user;
|
void *user;
|
||||||
HTTP_Response *response;
|
HTTP_Response *response;
|
||||||
ret = http_client_wait_response(&client, &result, &user, &response);
|
http_client_wait_response(&client, &result, &user, &response);
|
||||||
if (ret < 0) {
|
|
||||||
printf("Couldn't wait for response (%s)\n", http_strerror(ret));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result == HTTP_OK) {
|
if (result == HTTP_OK) {
|
||||||
printf("Received %d bytes\n", response->body.len);
|
printf("Received %d bytes\n", response->body.len);
|
||||||
|
|||||||
@@ -24,11 +24,7 @@ int main(void)
|
|||||||
|
|
||||||
HTTP_Request *request;
|
HTTP_Request *request;
|
||||||
HTTP_ResponseBuilder builder;
|
HTTP_ResponseBuilder builder;
|
||||||
int ret = http_server_wait_request(&server, &request, &builder);
|
http_server_wait_request(&server, &request, &builder);
|
||||||
if (ret < 0) {
|
|
||||||
fprintf(stderr, "Couldn't wait for request (%s)\n", http_strerror(ret));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
http_response_builder_status(builder, 200);
|
http_response_builder_status(builder, 200);
|
||||||
http_response_builder_body(builder, HTTP_STR("Hello, world!"));
|
http_response_builder_body(builder, HTTP_STR("Hello, world!"));
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
- Add connection timeouts
|
- Add connection timeouts
|
||||||
- Per RFC 6265, cookie values can be quoted. This parser would include the quotes in the value.
|
- Per RFC 6265, cookie values can be quoted. This parser would include the quotes in the value.
|
||||||
|
- Make sure that the proxy example doesn't stall
|
||||||
|
|||||||
+11
-14
@@ -225,6 +225,12 @@ void http_request_builder_target(HTTP_RequestBuilder builder,
|
|||||||
if (conn->state != HTTP_CLIENT_CONN_WAIT_URL)
|
if (conn->state != HTTP_CLIENT_CONN_WAIT_URL)
|
||||||
return; // Request line already written
|
return; // Request line already written
|
||||||
|
|
||||||
|
if (url.len == 0) {
|
||||||
|
conn->state = HTTP_CLIENT_CONN_COMPLETE;
|
||||||
|
conn->result = HTTP_ERROR_BADURL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a copy of the URL string so the parsed
|
// Allocate a copy of the URL string so the parsed
|
||||||
// URL pointers remain valid
|
// URL pointers remain valid
|
||||||
char *url_copy = malloc(url.len);
|
char *url_copy = malloc(url.len);
|
||||||
@@ -499,14 +505,11 @@ void http_client_register_events(HTTP_Client *client,
|
|||||||
socket_manager_register_events(&client->sockets, reg);
|
socket_manager_register_events(&client->sockets, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_client_process_events(HTTP_Client *client,
|
void http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
SocketEvent events[HTTP_CLIENT_CAPACITY];
|
||||||
int ret = socket_manager_translate_events(&client->sockets, events, reg);
|
int num_events = socket_manager_translate_events(&client->sockets, events, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
int num_events = ret;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -628,8 +631,6 @@ int http_client_process_events(HTTP_Client *client,
|
|||||||
client->num_ready++;
|
client->num_ready++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_client_next_response(HTTP_Client *client,
|
bool http_client_next_response(HTTP_Client *client,
|
||||||
@@ -686,7 +687,7 @@ void http_free_response(HTTP_Response *response)
|
|||||||
#define POLL poll
|
#define POLL poll
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int http_client_wait_response(HTTP_Client *client,
|
void http_client_wait_response(HTTP_Client *client,
|
||||||
int *result, void **user, HTTP_Response **response)
|
int *result, void **user, HTTP_Response **response)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -700,13 +701,9 @@ int http_client_wait_response(HTTP_Client *client,
|
|||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
int ret = http_client_process_events(client, ®);
|
http_client_process_events(client, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (http_client_next_response(client, result, user, response))
|
if (http_client_next_response(client, result, user, response))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -203,8 +203,8 @@ void http_client_register_events(HTTP_Client *client,
|
|||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
// I/O events to be triggered, so now the HTTP client
|
// I/O events to be triggered, so now the HTTP client
|
||||||
// can continue its buffering and flushing operations.
|
// can continue its buffering and flushing operations.
|
||||||
int http_client_process_events(HTTP_Client *client,
|
void http_client_process_events(HTTP_Client *client,
|
||||||
EventRegister *reg);
|
EventRegister reg);
|
||||||
|
|
||||||
// After some I/O events were processes, some responses
|
// After some I/O events were processes, some responses
|
||||||
// may be availabe. This function returns one of the
|
// may be availabe. This function returns one of the
|
||||||
@@ -217,7 +217,7 @@ bool http_client_next_response(HTTP_Client *client,
|
|||||||
int *result, void **user, HTTP_Response **response);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_client_wait_response(HTTP_Client *client,
|
void http_client_wait_response(HTTP_Client *client,
|
||||||
int *result, void **user, HTTP_Response **response);
|
int *result, void **user, HTTP_Response **response);
|
||||||
|
|
||||||
// Free a response object. You can't access its fields
|
// Free a response object. You can't access its fields
|
||||||
|
|||||||
+4
-5
@@ -1073,12 +1073,11 @@ static int parse_response(Scanner *s, HTTP_Response *res)
|
|||||||
|| !is_digit(s->src[s->cur+2])
|
|| !is_digit(s->src[s->cur+2])
|
||||||
|| s->src[s->cur+3] != ' ')
|
|| s->src[s->cur+3] != ' ')
|
||||||
return -1;
|
return -1;
|
||||||
s->cur += 5;
|
|
||||||
|
|
||||||
res->status =
|
res->status =
|
||||||
(s->src[s->cur-2] - '0') * 1 +
|
(s->src[s->cur+0] - '0') * 100 +
|
||||||
(s->src[s->cur-3] - '0') * 10 +
|
(s->src[s->cur+1] - '0') * 10 +
|
||||||
(s->src[s->cur-4] - '0') * 100;
|
(s->src[s->cur+2] - '0') * 1;
|
||||||
|
s->cur += 4;
|
||||||
|
|
||||||
// Parse reason phrase: HTAB / SP / VCHAR / obs-text
|
// Parse reason phrase: HTAB / SP / VCHAR / obs-text
|
||||||
// Note: obs-text (obsolete text, octets 0x80-0xFF) is not validated
|
// Note: obs-text (obsolete text, octets 0x80-0xFF) is not validated
|
||||||
|
|||||||
+6
-15
@@ -217,14 +217,11 @@ http_server_conn_process_events(HTTP_Server *server, HTTP_ServerConn *conn)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_process_events(HTTP_Server *server,
|
void http_server_process_events(HTTP_Server *server,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
SocketEvent events[HTTP_SERVER_CAPACITY];
|
SocketEvent events[HTTP_SERVER_CAPACITY];
|
||||||
int ret = socket_manager_translate_events(&server->sockets, events, reg);
|
int num_events = socket_manager_translate_events(&server->sockets, events, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
int num_events = ret;
|
|
||||||
|
|
||||||
for (int i = 0; i < num_events; i++) {
|
for (int i = 0; i < num_events; i++) {
|
||||||
|
|
||||||
@@ -265,8 +262,6 @@ int http_server_process_events(HTTP_Server *server,
|
|||||||
http_server_conn_process_events(server, conn);
|
http_server_conn_process_events(server, conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_server_next_request(HTTP_Server *server,
|
bool http_server_next_request(HTTP_Server *server,
|
||||||
@@ -285,7 +280,7 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int http_server_wait_request(HTTP_Server *server,
|
void http_server_wait_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
HTTP_Request **request, HTTP_ResponseBuilder *builder)
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -298,15 +293,11 @@ int http_server_wait_request(HTTP_Server *server,
|
|||||||
if (reg.num_polled > 0)
|
if (reg.num_polled > 0)
|
||||||
POLL(reg.polled, reg.num_polled, -1);
|
POLL(reg.polled, reg.num_polled, -1);
|
||||||
|
|
||||||
int ret = http_server_process_events(server, ®);
|
http_server_process_events(server, reg);
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (http_server_next_request(server, request, builder))
|
if (http_server_next_request(server, request, builder))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return HTTP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a connection pointer from a response builder.
|
// Get a connection pointer from a response builder.
|
||||||
@@ -495,7 +486,7 @@ void http_response_builder_body(HTTP_ResponseBuilder builder, HTTP_String str)
|
|||||||
if (conn == NULL)
|
if (conn == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (conn->state != HTTP_SERVER_CONN_WAIT_HEADER) {
|
if (conn->state == HTTP_SERVER_CONN_WAIT_HEADER) {
|
||||||
append_special_headers(conn);
|
append_special_headers(conn);
|
||||||
conn->state = HTTP_SERVER_CONN_WAIT_BODY;
|
conn->state = HTTP_SERVER_CONN_WAIT_BODY;
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -185,8 +185,8 @@ void http_server_register_events(HTTP_Server *server,
|
|||||||
// The caller has waited for poll() to return and some
|
// The caller has waited for poll() to return and some
|
||||||
// I/O events to be triggered, so now the HTTP server
|
// I/O events to be triggered, so now the HTTP server
|
||||||
// can continue its buffering and flushing operations.
|
// can continue its buffering and flushing operations.
|
||||||
int http_server_process_events(HTTP_Server *server,
|
void http_server_process_events(HTTP_Server *server,
|
||||||
EventRegister *reg);
|
EventRegister reg);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HTTP_Server *server;
|
HTTP_Server *server;
|
||||||
@@ -206,7 +206,7 @@ bool http_server_next_request(HTTP_Server *server,
|
|||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// TODO: comment
|
// TODO: comment
|
||||||
int http_server_wait_request(HTTP_Server *server,
|
void http_server_wait_request(HTTP_Server *server,
|
||||||
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
HTTP_Request **request, HTTP_ResponseBuilder *builder);
|
||||||
|
|
||||||
// This function is called to set the status code of
|
// This function is called to set the status code of
|
||||||
|
|||||||
+9
-11
@@ -777,16 +777,16 @@ static Socket *handle_to_socket(SocketManager *sm, SocketHandle handle)
|
|||||||
|
|
||||||
int socket_manager_translate_events(
|
int socket_manager_translate_events(
|
||||||
SocketManager *sm, SocketEvent *events,
|
SocketManager *sm, SocketEvent *events,
|
||||||
EventRegister *reg)
|
EventRegister reg)
|
||||||
{
|
{
|
||||||
int num_events = 0;
|
int num_events = 0;
|
||||||
for (int i = 0; i < reg->num_polled; i++) {
|
for (int i = 0; i < reg.num_polled; i++) {
|
||||||
|
|
||||||
if (!reg->polled[i].revents)
|
if (!reg.polled[i].revents)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (reg->polled[i].fd == sm->plain_sock ||
|
if (reg.polled[i].fd == sm->plain_sock ||
|
||||||
reg->polled[i].fd == sm->secure_sock) {
|
reg.polled[i].fd == sm->secure_sock) {
|
||||||
|
|
||||||
// We only listen for input events from the listener
|
// We only listen for input events from the listener
|
||||||
// if the socket pool isn't fool. This ensures that
|
// if the socket pool isn't fool. This ensures that
|
||||||
@@ -802,7 +802,7 @@ int socket_manager_translate_events(
|
|||||||
|
|
||||||
// Determine whether the event came from
|
// Determine whether the event came from
|
||||||
// the encrypted listener or not.
|
// the encrypted listener or not.
|
||||||
bool secure = (reg->polled[i].fd == sm->secure_sock);
|
bool secure = (reg.polled[i].fd == sm->secure_sock);
|
||||||
|
|
||||||
Socket *s = sm->sockets;
|
Socket *s = sm->sockets;
|
||||||
while (s->state != SOCKET_STATE_FREE) {
|
while (s->state != SOCKET_STATE_FREE) {
|
||||||
@@ -810,7 +810,7 @@ int socket_manager_translate_events(
|
|||||||
assert(s - sm->sockets < + sm->max_used);
|
assert(s - sm->sockets < + sm->max_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
NATIVE_SOCKET sock = accept(reg->polled[i].fd, NULL, NULL);
|
NATIVE_SOCKET sock = accept(reg.polled[i].fd, NULL, NULL);
|
||||||
if (sock == NATIVE_SOCKET_INVALID)
|
if (sock == NATIVE_SOCKET_INVALID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -843,7 +843,7 @@ int socket_manager_translate_events(
|
|||||||
|
|
||||||
sm->num_used++;
|
sm->num_used++;
|
||||||
|
|
||||||
} else if (reg->polled[i].fd == sm->wait_sock) {
|
} else if (reg.polled[i].fd == sm->wait_sock) {
|
||||||
|
|
||||||
// Consume one byte from the wakeup signal
|
// Consume one byte from the wakeup signal
|
||||||
char byte;
|
char byte;
|
||||||
@@ -854,9 +854,7 @@ int socket_manager_translate_events(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
Socket *s = reg.ptrs[i];
|
||||||
Socket *s = reg->ptrs[i];
|
|
||||||
if (reg->polled[i].revents)
|
|
||||||
socket_update(s);
|
socket_update(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -289,7 +289,7 @@ void socket_manager_register_events(SocketManager *sm,
|
|||||||
// socket structs provided to the socket manager
|
// socket structs provided to the socket manager
|
||||||
// via the init function.
|
// via the init function.
|
||||||
int socket_manager_translate_events(SocketManager *sm,
|
int socket_manager_translate_events(SocketManager *sm,
|
||||||
SocketEvent *events, EventRegister *reg);
|
SocketEvent *events, EventRegister reg);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CONNECT_TARGET_NAME,
|
CONNECT_TARGET_NAME,
|
||||||
|
|||||||
Reference in New Issue
Block a user