|
@@ -74,6 +74,7 @@ typedef struct {
|
|
|
int content_length;
|
|
int content_length;
|
|
|
char content_type[64];
|
|
char content_type[64];
|
|
|
unsigned keepalive: 1;
|
|
unsigned keepalive: 1;
|
|
|
|
|
+ unsigned proxy: 1;
|
|
|
char head[HTTP_MAX_HEAD_LENGTH];
|
|
char head[HTTP_MAX_HEAD_LENGTH];
|
|
|
int head_len;
|
|
int head_len;
|
|
|
// body
|
|
// body
|
|
@@ -92,28 +93,32 @@ static int http_request_dump(http_conn_t* conn, char* buf, int len) {
|
|
|
http_msg_t* msg = &conn->request;
|
|
http_msg_t* msg = &conn->request;
|
|
|
int offset = 0;
|
|
int offset = 0;
|
|
|
// request line
|
|
// request line
|
|
|
- const char* pos = strstr(msg->path, "://");
|
|
|
|
|
- pos = pos ? pos + 3 : msg->path;
|
|
|
|
|
- const char* path = strchr(pos, '/');
|
|
|
|
|
|
|
+ const char* path = msg->path;
|
|
|
|
|
+ if (msg->proxy) {
|
|
|
|
|
+ const char* pos = strstr(msg->path, "://");
|
|
|
|
|
+ pos = pos ? pos + 3 : msg->path;
|
|
|
|
|
+ path = strchr(pos, '/');
|
|
|
|
|
+ }
|
|
|
if (path == NULL) path = "/";
|
|
if (path == NULL) path = "/";
|
|
|
offset += snprintf(buf + offset, len - offset, "%s %s HTTP/%d.%d\r\n", msg->method, path, msg->major_version, msg->minor_version);
|
|
offset += snprintf(buf + offset, len - offset, "%s %s HTTP/%d.%d\r\n", msg->method, path, msg->major_version, msg->minor_version);
|
|
|
// headers
|
|
// headers
|
|
|
- /*
|
|
|
|
|
- offset += snprintf(buf + offset, len - offset, "Connection: %s\r\n", msg->keepalive ? "keep-alive" : "close");
|
|
|
|
|
- if (msg->content_length > 0) {
|
|
|
|
|
- offset += snprintf(buf + offset, len - offset, "Content-Length: %d\r\n", msg->content_length);
|
|
|
|
|
- }
|
|
|
|
|
- if (*msg->content_type) {
|
|
|
|
|
- offset += snprintf(buf + offset, len - offset, "Content-Type: %s\r\n", msg->content_type);
|
|
|
|
|
- }
|
|
|
|
|
- */
|
|
|
|
|
- if (msg->head_len) {
|
|
|
|
|
- memcpy(buf + offset, msg->head, msg->head_len);
|
|
|
|
|
- offset += msg->head_len;
|
|
|
|
|
|
|
+ if (msg->proxy) {
|
|
|
|
|
+ if (msg->head_len) {
|
|
|
|
|
+ memcpy(buf + offset, msg->head, msg->head_len);
|
|
|
|
|
+ offset += msg->head_len;
|
|
|
|
|
+ }
|
|
|
|
|
+ char peeraddrstr[SOCKADDR_STRLEN] = {0};
|
|
|
|
|
+ SOCKADDR_STR(hio_peeraddr(conn->io), peeraddrstr);
|
|
|
|
|
+ offset += snprintf(buf + offset, len - offset, "X-Origin-IP: %s\r\n", peeraddrstr);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ offset += snprintf(buf + offset, len - offset, "Connection: %s\r\n", msg->keepalive ? "keep-alive" : "close");
|
|
|
|
|
+ if (msg->content_length > 0) {
|
|
|
|
|
+ offset += snprintf(buf + offset, len - offset, "Content-Length: %d\r\n", msg->content_length);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (*msg->content_type) {
|
|
|
|
|
+ offset += snprintf(buf + offset, len - offset, "Content-Type: %s\r\n", msg->content_type);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- char peeraddrstr[SOCKADDR_STRLEN] = {0};
|
|
|
|
|
- SOCKADDR_STR(hio_peeraddr(conn->io), peeraddrstr);
|
|
|
|
|
- offset += snprintf(buf + offset, len - offset, "X-Origin-IP: %s\r\n", peeraddrstr);
|
|
|
|
|
// TODO: Add your headers
|
|
// TODO: Add your headers
|
|
|
offset += snprintf(buf + offset, len - offset, "\r\n");
|
|
offset += snprintf(buf + offset, len - offset, "\r\n");
|
|
|
// body
|
|
// body
|
|
@@ -152,7 +157,7 @@ static bool parse_http_head(http_conn_t* conn, char* buf, int len) {
|
|
|
req->content_length = atoi(val);
|
|
req->content_length = atoi(val);
|
|
|
} else if (stricmp(key, "Content-Type") == 0) {
|
|
} else if (stricmp(key, "Content-Type") == 0) {
|
|
|
strncpy(req->content_type, val, sizeof(req->content_type) - 1);
|
|
strncpy(req->content_type, val, sizeof(req->content_type) - 1);
|
|
|
- } else if (stricmp(key, "Proxy-Connection") == 0) {
|
|
|
|
|
|
|
+ } else if (stricmp(key, "Connection") == 0 || stricmp(key, "Proxy-Connection") == 0) {
|
|
|
if (stricmp(val, "close") == 0) {
|
|
if (stricmp(val, "close") == 0) {
|
|
|
req->keepalive = 0;
|
|
req->keepalive = 0;
|
|
|
}
|
|
}
|
|
@@ -196,20 +201,22 @@ static int on_head_end(http_conn_t* conn) {
|
|
|
char backend_host[64] = {0};
|
|
char backend_host[64] = {0};
|
|
|
strcpy(backend_host, req->host);
|
|
strcpy(backend_host, req->host);
|
|
|
int backend_port = 80;
|
|
int backend_port = 80;
|
|
|
- int backend_ssl = strncmp(req->path, "https", 5) == 0 ? 1 : 0;
|
|
|
|
|
char* pos = strchr(backend_host, ':');
|
|
char* pos = strchr(backend_host, ':');
|
|
|
if (pos) {
|
|
if (pos) {
|
|
|
*pos = '\0';
|
|
*pos = '\0';
|
|
|
backend_port = atoi(pos + 1);
|
|
backend_port = atoi(pos + 1);
|
|
|
}
|
|
}
|
|
|
- // printf("upstream %s:%d\n", backend_host, backend_port);
|
|
|
|
|
if (backend_port == proxy_port &&
|
|
if (backend_port == proxy_port &&
|
|
|
(strcmp(backend_host, proxy_host) == 0 ||
|
|
(strcmp(backend_host, proxy_host) == 0 ||
|
|
|
strcmp(backend_host, "localhost") == 0 ||
|
|
strcmp(backend_host, "localhost") == 0 ||
|
|
|
strcmp(backend_host, "127.0.0.1") == 0)) {
|
|
strcmp(backend_host, "127.0.0.1") == 0)) {
|
|
|
- fprintf(stderr, "Cound not to upstream proxy server itself!\n");
|
|
|
|
|
- return -2;
|
|
|
|
|
|
|
+ req->proxy = 0;
|
|
|
|
|
+ return 0;
|
|
|
}
|
|
}
|
|
|
|
|
+ // NOTE: blew for proxy
|
|
|
|
|
+ req->proxy = 1;
|
|
|
|
|
+ int backend_ssl = strncmp(req->path, "https", 5) == 0 ? 1 : 0;
|
|
|
|
|
+ // printf("upstream %s:%d\n", backend_host, backend_port);
|
|
|
hloop_t* loop = hevent_loop(conn->io);
|
|
hloop_t* loop = hevent_loop(conn->io);
|
|
|
// hio_t* upstream_io = hio_setup_tcp_upstream(conn->io, backend_host, backend_port, backend_ssl);
|
|
// hio_t* upstream_io = hio_setup_tcp_upstream(conn->io, backend_host, backend_port, backend_ssl);
|
|
|
hio_t* upstream_io = hio_create_socket(loop, backend_host, backend_port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
|
|
hio_t* upstream_io = hio_create_socket(loop, backend_host, backend_port, HIO_TYPE_TCP, HIO_CLIENT_SIDE);
|
|
@@ -230,10 +237,23 @@ static int on_head_end(http_conn_t* conn) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int on_body(http_conn_t* conn, void* buf, int readbytes) {
|
|
static int on_body(http_conn_t* conn, void* buf, int readbytes) {
|
|
|
- hio_write_upstream(conn->io, buf, readbytes);
|
|
|
|
|
|
|
+ http_msg_t* req = &conn->request;
|
|
|
|
|
+ if (req->proxy) {
|
|
|
|
|
+ hio_write_upstream(conn->io, buf, readbytes);
|
|
|
|
|
+ }
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static int on_request(http_conn_t* conn) {
|
|
|
|
|
+ // NOTE: just reply 403, please refer to examples/tinyhttpd if you want to reply other.
|
|
|
|
|
+ http_msg_t* req = &conn->request;
|
|
|
|
|
+ char buf[256] = {0};
|
|
|
|
|
+ int len = snprintf(buf, sizeof(buf), "HTTP/%d.%d %d %s\r\nContent-Length: 0\r\n\r\n",
|
|
|
|
|
+ req->major_version, req->minor_version, 403, "Forbidden");
|
|
|
|
|
+ hio_write(conn->io, buf, len);
|
|
|
|
|
+ return 403;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void on_close(hio_t* io) {
|
|
static void on_close(hio_t* io) {
|
|
|
// printf("on_close fd=%d error=%d\n", hio_fd(io), hio_error(io));
|
|
// printf("on_close fd=%d error=%d\n", hio_fd(io), hio_error(io));
|
|
|
http_conn_t* conn = (http_conn_t*)hevent_userdata(io);
|
|
http_conn_t* conn = (http_conn_t*)hevent_userdata(io);
|
|
@@ -305,10 +325,20 @@ static void on_recv(hio_t* io, void* buf, int readbytes) {
|
|
|
}
|
|
}
|
|
|
if (req->content_length == 0) {
|
|
if (req->content_length == 0) {
|
|
|
conn->state = s_end;
|
|
conn->state = s_end;
|
|
|
|
|
+ if (req->proxy) {
|
|
|
|
|
+ // NOTE: wait upstream connect!
|
|
|
|
|
+ } else {
|
|
|
|
|
+ goto s_end;
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
conn->state = s_body;
|
|
conn->state = s_body;
|
|
|
- // NOTE: start read body on_upstream_connect
|
|
|
|
|
- // hio_read_start(io);
|
|
|
|
|
|
|
+ if (req->proxy) {
|
|
|
|
|
+ // NOTE: start read body on_upstream_connect
|
|
|
|
|
+ // hio_read_start(io);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // WARN: too large content_length should read multiple times!
|
|
|
|
|
+ hio_readbytes(io, req->content_length);
|
|
|
|
|
+ }
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case s_body:
|
|
case s_body:
|
|
@@ -326,7 +356,15 @@ static void on_recv(hio_t* io, void* buf, int readbytes) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
case s_end:
|
|
case s_end:
|
|
|
|
|
+s_end:
|
|
|
// printf("s_end\n");
|
|
// printf("s_end\n");
|
|
|
|
|
+ // received complete request
|
|
|
|
|
+ if (req->proxy) {
|
|
|
|
|
+ // NOTE: reply by upstream
|
|
|
|
|
+ } else {
|
|
|
|
|
+ on_request(conn);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (hio_is_closed(io)) return;
|
|
|
if (req->keepalive) {
|
|
if (req->keepalive) {
|
|
|
// Connection: keep-alive\r\n
|
|
// Connection: keep-alive\r\n
|
|
|
// reset and receive next request
|
|
// reset and receive next request
|
|
@@ -336,8 +374,11 @@ static void on_recv(hio_t* io, void* buf, int readbytes) {
|
|
|
hio_readline(io);
|
|
hio_readline(io);
|
|
|
} else {
|
|
} else {
|
|
|
// Connection: close\r\n
|
|
// Connection: close\r\n
|
|
|
- // NOTE: wait upstream close!
|
|
|
|
|
- // hio_close(io);
|
|
|
|
|
|
|
+ if (req->proxy) {
|
|
|
|
|
+ // NOTE: wait upstream close!
|
|
|
|
|
+ } else {
|
|
|
|
|
+ hio_close(io);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
break;
|
|
break;
|
|
|
default: break;
|
|
default: break;
|