1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
#include <uwsgi.h>
#ifdef UWSGI_ROUTING
extern struct uwsgi_server uwsgi;
static int uwsgi_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
struct uwsgi_buffer *ub = NULL;
// mark a route request
wsgi_req->via = UWSGI_VIA_ROUTE;
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub_addr) return UWSGI_ROUTE_BREAK;
struct uwsgi_buffer *ub_url = NULL;
if (ur->data3_len) {
ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len);
if (!ub_url) {
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
}
// convert the wsgi_request to an http proxy request
if (ur->custom & 0x02) {
ub = uwsgi_buffer_new(uwsgi.page_size);
}
else if (ur->custom & 0x04) {
ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
}
else {
ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0);
}
if (!ub) {
if (ub_url) uwsgi_buffer_destroy(ub_url);
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_NEXT;
}
if (ub_url) uwsgi_buffer_destroy(ub_url);
// amount of body to send
size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains;
// append remaining body...
if (wsgi_req->proto_parser_remains > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_NEXT;
}
wsgi_req->post_pos += wsgi_req->proto_parser_remains;
wsgi_req->proto_parser_remains = 0;
}
// ok now if have offload threads, directly use them
if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) {
// append buffered body
if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) {
if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) {
uwsgi_buffer_destroy(ub);
uwsgi_log("unable to generate http request for %s\n", ub_addr->buf);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_NEXT;
}
}
// if we have a CONNECT request, let's confirm it to the client
if (ur->custom & 0x02) {
if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end;
// no need to check for return value
uwsgi_response_write_headers_do(wsgi_req);
}
if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) {
wsgi_req->via = UWSGI_VIA_OFFLOAD;
wsgi_req->status = 202;
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
}
if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) {
uwsgi_log("error routing request to http server %s\n", ub_addr->buf);
}
end:
uwsgi_buffer_destroy(ub);
uwsgi_buffer_destroy(ub_addr);
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_http(struct uwsgi_route *ur, char *args) {
ur->func = uwsgi_routing_func_http;
ur->data = (void *) args;
ur->data_len = strlen(args);
char *comma = strchr(ur->data, ',');
if (comma) {
*comma = 0;
ur->data_len = strlen(ur->data);
ur->data2 = comma+1;
comma = strchr(ur->data2, ',');
if (comma) {
*comma = 0;
ur->data3 = comma+1;
ur->data3_len = strlen(ur->data3);
}
ur->data2_len = strlen(ur->data2);
}
return 0;
}
static int uwsgi_router_proxyhttp(struct uwsgi_route *ur, char *args) {
ur->custom = 0x1;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_proxyhttp_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x1|0x02;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_http_connect(struct uwsgi_route *ur, char *args) {
ur->custom = 0x02;
return uwsgi_router_http(ur, args);
}
static int uwsgi_router_httpdumb(struct uwsgi_route *ur, char *args) {
ur->custom = 0x04;
return uwsgi_router_http(ur, args);
}
static void router_http_register(void) {
uwsgi_register_router("http", uwsgi_router_http);
uwsgi_register_router("httpdumb", uwsgi_router_httpdumb);
uwsgi_register_router("proxyhttp", uwsgi_router_proxyhttp);
uwsgi_register_router("httpconnect", uwsgi_router_http_connect);
uwsgi_register_router("proxyhttpconnect", uwsgi_router_proxyhttp_connect);
}
struct uwsgi_plugin router_http_plugin = {
.name = "router_http",
.on_load = router_http_register,
};
#else
struct uwsgi_plugin router_http_plugin = {
.name = "router_http",
};
#endif
|