static uint16_t uwsgi_mongrel2_json_add(struct wsgi_request *wsgi_req, json_t * node, const char *json_key, char *key, uint16_t keylen, char **extra, size_t * extra_len) { char *json_val; json_t *json_value = json_object_get(node, json_key); if (json_is_string(json_value)) { json_val = (char *) json_string_value(json_value); // invalid value ? if (strlen(json_val) > 0xffff) return 0; if (extra) { *extra = json_val; *extra_len = strlen(json_val); } return proto_base_add_uwsgi_var(wsgi_req, key, keylen, json_val, strlen(json_val)); } return 0; }
static int uwsgi_mongrel2_json_parse(json_t * root, struct wsgi_request *wsgi_req) { char *json_val; char *query_string = NULL; size_t query_string_len = 0; size_t script_name_len = 0; void *json_iter; char *json_key; json_t *json_value; if ((json_val = uwsgi_mongrel2_json_get_string(root, "METHOD"))) { if (!strcmp(json_val, "JSON")) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, json_val, strlen(json_val)); } // pretty easy, we get the file and we map it to wsgi_req->post_file, uWSGI read api will automatically use this if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-done"))) { wsgi_req->post_file = fopen(json_val, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(json_val); return -1; } } else if (uwsgi_mongrel2_json_get_string(root, "x-mongrel2-upload-start")) { return -1; } wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "VERSION", "SERVER_PROTOCOL", 15, NULL, NULL); wsgi_req->uh->pktsize += uwsgi_mongrel2_json_add(wsgi_req, root, "QUERY", "QUERY_STRING", 12, &query_string, &query_string_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // set SCRIPT_NAME to an empty value wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); if ((json_val = uwsgi_mongrel2_json_get_string(root, "PATH"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, json_val + script_name_len, strlen(json_val + script_name_len)); if (query_string_len) { char *request_uri = uwsgi_concat3n(json_val, strlen(json_val), "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, strlen(json_val) + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "URL_SCHEME"))) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "UWSGI_SCHEME", 12, json_val, strlen(json_val)); } if ((json_val = uwsgi_mongrel2_json_get_string(root, "host"))) { char *colon = strchr(json_val, ':'); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, strlen(colon + 1)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "x-forwarded-for"))) { char *colon = strchr(json_val, ','); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - json_val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, json_val, strlen(json_val)); } } if ((json_val = uwsgi_mongrel2_json_get_string(root, "content-length"))) { wsgi_req->post_cl = atoi(json_val); } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); json_iter = json_object_iter(root); while (json_iter) { json_key = (char *) json_object_iter_key(json_iter); // is it a header ? if (json_key[0] >= 97) { json_value = json_object_iter_value(json_iter); if (json_is_string(json_value)) { json_val = (char *) json_string_value(json_value); wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, json_key, strlen(json_key), json_val, strlen(json_val)); } } json_iter = json_object_iter_next(root, json_iter); } return 0; }
// dumb/fake tnetstring implementation...all is a string static int uwsgi_mongrel2_tnetstring_parse(struct wsgi_request *wsgi_req, char *buf, int len) { char *ptr = buf; char *watermark = buf + len; char *key = NULL; size_t keylen = 0; char *val = NULL; size_t vallen = 0; uint16_t script_name_len = 0; char *query_string = NULL; uint16_t query_string_len = 0; int async_upload = 0; // set an empty SCRIPT_NAME wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SCRIPT_NAME", 11, "", 0); while (ptr < watermark) { ptr = uwsgi_netstring(ptr, len - (ptr - buf), &key, &keylen); if (ptr == NULL) break; // empty keys are not allowed if (keylen == 0) break; if (ptr >= watermark) break; ptr = uwsgi_netstring(ptr, len - (ptr - buf), &val, &vallen); if (ptr == NULL) break; if (key[0] < 97) { if (!uwsgi_strncmp("METHOD", 6, key, keylen)) { if (!uwsgi_strncmp("JSON", 4, val, vallen)) { return -1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_METHOD", 14, val, vallen); } else if (!uwsgi_strncmp("VERSION", 7, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PROTOCOL", 15, val, vallen); } else if (!uwsgi_strncmp("QUERY", 5, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, val, vallen); query_string = val; query_string_len = vallen; } else if (!uwsgi_strncmp("PATH", 4, key, keylen)) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "PATH_INFO", 9, val + script_name_len, vallen - script_name_len); if (query_string_len) { char *request_uri = uwsgi_concat3n(val, vallen, "?", 1, query_string, query_string_len); wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, request_uri, vallen + 1 + query_string_len); free(request_uri); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REQUEST_URI", 11, val, vallen); } } } else { // add header if (!uwsgi_strncmp("host", 4, key, keylen)) { char *colon = memchr(val, ':', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, colon + 1, vallen - ((colon + 1) - val)); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_PORT", 11, "80", 2); } } else if (!uwsgi_strncmp("content-length", 14, key, keylen)) { wsgi_req->post_cl = uwsgi_str_num(val, vallen); } else if (!uwsgi_strncmp("x-mongrel2-upload-done", 22, key, keylen)) { char *post_filename = uwsgi_concat2n(val, vallen, "", 0); wsgi_req->post_file = fopen(post_filename, "r"); if (!wsgi_req->post_file) { uwsgi_error_open(post_filename); wsgi_req->do_not_log = 1; } async_upload += 2; free(post_filename); } else if (!uwsgi_strncmp("x-forwarded-for", 15, key, keylen)) { char *colon = memchr(val, ',', vallen); if (colon) { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, colon + 1, (colon + 1) - val); } else { wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "REMOTE_ADDR", 11, val, vallen); } } else if (!uwsgi_strncmp("x-mongrel2-upload-start", 23, key, keylen)) { async_upload += 1; } wsgi_req->uh->pktsize += proto_base_add_uwsgi_header(wsgi_req, key, keylen, val, vallen); } } wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "SERVER_NAME", 11, uwsgi.hostname, uwsgi.hostname_len); if (query_string == NULL) { // always set QUERY_STRING wsgi_req->uh->pktsize += proto_base_add_uwsgi_var(wsgi_req, "QUERY_STRING", 12, "", 0); } // reject uncomplete upload if (async_upload == 1) { return -1; } return 0; }
static int scgi_parse(struct wsgi_request *wsgi_req) { char *buf = wsgi_req->proto_parser_buf; size_t len = wsgi_req->proto_parser_pos; size_t i; size_t scgi_len = 0; for(i=0;i<len;i++) { if (buf[i] == ':') { scgi_len = uwsgi_str_num(buf, i); if (scgi_len == 0) return -1; goto keyval; } } return 0; keyval: if (i + scgi_len + 1 > len) { return 0; } i++; size_t vars = i; char *key = buf + i; size_t keylen = 0; char *value = NULL; size_t vallen = 0; for(i=vars;i<vars+scgi_len;i++) { if (key == NULL) { key = buf + i; } else if (keylen > 0 && value == NULL) { value = buf + i; } if (buf[i] == 0) { if (value) { vallen = (buf+i) - value; uint16_t pktsize = proto_base_add_uwsgi_var(wsgi_req, key, keylen, value, vallen); if (pktsize == 0) return -1; wsgi_req->uh->pktsize += pktsize; key = NULL; value = NULL; keylen = 0; vallen = 0; } else { keylen = (buf+i) - key; value = NULL; } } } if (buf[i] == ',') { if (len > i+1) { wsgi_req->proto_parser_remains = len-(i+1); wsgi_req->proto_parser_remains_buf = buf + i + 1; } return 1; } return -1; }