Esempio n. 1
0
int uwsgi_add_expires_uri(struct wsgi_request *wsgi_req, struct stat *st) {

	struct uwsgi_dyn_dict *udd = uwsgi.static_expires_uri;
	time_t now = wsgi_req->start_of_request / 1000000;
	// 30+1
	char expires[31];

	while (udd) {
		if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
			int delta = uwsgi_str_num(udd->value, udd->vallen);
			int size = set_http_date(now + delta, expires);
			if (size > 0) {
				if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
			}
			return 0;
		}
		udd = udd->next;
	}

	udd = uwsgi.static_expires_uri_mtime;
	while (udd) {
		if (uwsgi_regexp_match(udd->pattern, udd->pattern_extra, wsgi_req->uri, wsgi_req->uri_len) >= 0) {
			int delta = uwsgi_str_num(udd->value, udd->vallen);
			int size = set_http_date(st->st_mtime + delta, expires);
			if (size > 0) {
				if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
			}
			return 0;
		}
		udd = udd->next;
	}

	return 0;
}
Esempio n. 2
0
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
#ifdef UWSGI_SSL
	char sha1[20];
	if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
	if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
	if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
        if (origin_len > 0) {
		if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
        }
        else {
		if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
        }
	// generate websockets sha1 and encode it to base64
        if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
	size_t b64_len = 0;
        char *b64 = uwsgi_base64_encode(sha1, 20, &b64_len);
	if (!b64) return -1;

	if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Accept", 20, b64, b64_len)) {
		free(b64);
		return -1;
	}
	free(b64);

	wsgi_req->websocket_last_pong = uwsgi_now();

	return uwsgi_response_write_headers_do(wsgi_req);
#else
	uwsgi_log("you need to build uWSGI with SSL support to use the websocket handshake api function !!!\n");
	return -1;
#endif
}
Esempio n. 3
0
int uwsgi_add_expires_type(struct wsgi_request *wsgi_req, char *mime_type, int mime_type_len, struct stat *st) {

	struct uwsgi_dyn_dict *udd = uwsgi.static_expires_type;
	time_t now = wsgi_req->start_of_request / 1000000;
	// 30+1
	char expires[31];

	while (udd) {
		if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
			int delta = uwsgi_str_num(udd->value, udd->vallen);
			int size = set_http_date(now + delta, expires);
			if (size > 0) {
				if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
			}
			return 0;
		}
		udd = udd->next;
	}

	udd = uwsgi.static_expires_type_mtime;
	while (udd) {
		if (!uwsgi_strncmp(udd->key, udd->keylen, mime_type, mime_type_len)) {
			int delta = uwsgi_str_num(udd->value, udd->vallen);
			int size = set_http_date(st->st_mtime + delta, expires);
			if (size > 0) {
				if (uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, size)) return -1;
			}
			return 0;
		}
		udd = udd->next;
	}

	return 0;
}
Esempio n. 4
0
Response& Response::flush()
{
    if ( !status_.empty() )
    {
        uwsgi_response_prepare_headers(
            r_, 
            (char*)status_.c_str(), status_.size()
        );
        status_ = "";
    }
    
    for ( size_t i = 0; i < headers_.size(); i++)
    {
        const std::string& key = headers_[i].first;
        const std::string& val = headers_[i].second;

        uwsgi_response_add_header(
            r_, 
            (char*)key.c_str(), key.size(), 
            (char*)val.c_str(), val.size()
        );    
        headers_.clear();
    }

    if ( !cookies_.empty())
    {
        for ( size_t i = 0; i < cookies_.size(); i++ )
        {    
            std::string key = "Set-Cookie";
            std::string val = cookies_[i].str();
            uwsgi_response_add_header(
                r_, 
                (char*)key.c_str(), key.size(), 
                (char*)val.c_str(), val.size()
            );        
        }        
        cookies_.clear(); 
    }    
    
    if ( !body_.empty() )
    {
        uwsgi_response_write_body_do(
            r_, 
            (char*)body_.c_str(), body_.size()
        );        
        body_ = "";
    }    
    return *this;
}
Esempio n. 5
0
int uwsgi_response_write_headers_do(struct wsgi_request *wsgi_req) {
	if (wsgi_req->headers_sent || !wsgi_req->headers || wsgi_req->response_size || wsgi_req->write_errors) {
		return UWSGI_OK;
	}

	struct uwsgi_string_list *ah = uwsgi.additional_headers;
	while(ah) {
		if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
                ah = ah->next;
        }

        ah = wsgi_req->additional_headers;
        while(ah) {
		if (uwsgi_response_add_header(wsgi_req, NULL, 0, ah->value, ah->len)) return -1;
                ah = ah->next;
        }


	if (wsgi_req->socket->proto_fix_headers(wsgi_req)) { wsgi_req->write_errors++ ; return -1;}

	for(;;) {
                int ret = wsgi_req->socket->proto_write_headers(wsgi_req, wsgi_req->headers->buf, wsgi_req->headers->pos);
                if (ret < 0) {
                        if (!uwsgi.ignore_write_errors) {
                                uwsgi_error("uwsgi_response_write_headers_do()");
                        }
			wsgi_req->write_errors++;
                        return -1;
                }
                if (ret == UWSGI_OK) {
                        break;
                }
                ret = uwsgi_wait_write_req(wsgi_req);
                if (ret < 0) { wsgi_req->write_errors++; return -1;}
                if (ret == 0) {
			uwsgi_log("uwsgi_response_write_headers_do() TIMEOUT !!!\n");
			wsgi_req->write_errors++;
			return -1;
		}
        }

        wsgi_req->headers_size += wsgi_req->write_pos;
	// reset for the next write
        wsgi_req->write_pos = 0;
	wsgi_req->headers_sent = 1;

        return UWSGI_OK;
}
Esempio n. 6
0
static int sapi_uwsgi_send_headers(sapi_headers_struct *sapi_headers)
{
	sapi_header_struct *h;
	zend_llist_position pos;

	if (SG(request_info).no_headers == 1) {
                return SAPI_HEADER_SENT_SUCCESSFULLY;
        }

	struct wsgi_request *wsgi_req = (struct wsgi_request *) SG(server_context);

	if (!SG(sapi_headers).http_status_line) {
		char status[4];
		int hrc = SG(sapi_headers).http_response_code;
		if (!hrc) hrc = 200;
		uwsgi_num2str2n(hrc, status, 4);
		uwsgi_response_prepare_headers(wsgi_req, status, 3);
	}
	else {
		char *sl = SG(sapi_headers).http_status_line;
		uwsgi_response_prepare_headers(wsgi_req, sl, strlen(sl));
	}
	
	h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
	while (h) {
		uwsgi_response_add_header(wsgi_req, NULL, 0, h->header, h->header_len);
		h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
	}

	return SAPI_HEADER_SENT_SUCCESSFULLY;
}
Esempio n. 7
0
static int uwsgi_routing_func_basicauth(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {

	// skip if already authenticated
	if (wsgi_req->remote_user_len > 0) {
		return UWSGI_ROUTE_NEXT;
	}


	if (wsgi_req->authorization_len > 7 && ur->data2_len > 0) {
		if (strncmp(wsgi_req->authorization, "Basic ", 6))
			goto forbidden;

		size_t auth_len = 0;
		char *auth = uwsgi_base64_decode(wsgi_req->authorization+6, wsgi_req->authorization_len-6, &auth_len);
		if (auth) {
			if (!ur->custom) {
				// check htpasswd-like file
				uint16_t ulen = htpasswd_check(ur->data2, auth);
				if (ulen > 0) {
					wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ulen); 
					if (!wsgi_req->remote_user) {
						free(auth);
						goto forbidden;
					}
					wsgi_req->remote_user_len = ulen;
				}
				else if (ur->data3_len == 0) {
					free(auth);
					goto forbidden;
				}
			}
			else {
				if (!uwsgi_strncmp(auth, auth_len, ur->data2, ur->data2_len)) {
					wsgi_req->remote_user = uwsgi_req_append(wsgi_req, "REMOTE_USER", 11, auth, ur->custom); 
					if (!wsgi_req->remote_user) {
						free(auth);
						goto forbidden;
					}
					wsgi_req->remote_user_len = ur->custom;
				}
				else if (ur->data3_len == 0) {
					free(auth);
					goto forbidden;
				}
			}
			free(auth);
			return UWSGI_ROUTE_NEXT;
		}
	}

forbidden:
	if (uwsgi_response_prepare_headers(wsgi_req, "401 Authorization Required", 26)) goto end;
	char *realm = uwsgi_concat3n("Basic realm=\"", 13, ur->data, ur->data_len, "\"", 1);
	// no need to check for errors
	uwsgi_response_add_header(wsgi_req, "WWW-Authenticate", 16, realm, 13 + ur->data_len + 1);
	free(realm);
	uwsgi_response_write_body_do(wsgi_req, "Unauthorized", 12);
end:
	return UWSGI_ROUTE_BREAK;
}
Esempio n. 8
0
int uwsgi_response_add_content_length(struct wsgi_request *wsgi_req, uint64_t cl) {
	char buf[sizeof(UMAX64_STR)+1];
        int ret = snprintf(buf, sizeof(UMAX64_STR)+1, "%llu", (unsigned long long) cl);
        if (ret <= 0 || ret > (int) (sizeof(UMAX64_STR)+1)) {
		wsgi_req->write_errors++;
                return -1;
        }
	return uwsgi_response_add_header(wsgi_req, "Content-Length", 14, buf, ret); 
}
Esempio n. 9
0
File: writer.c Progetto: JuanS/uwsgi
int uwsgi_response_add_last_modified(struct wsgi_request *wsgi_req, uint64_t t) {
        // 30+1
        char lm[31];
        int len = uwsgi_http_date((time_t) t, lm);
        if (!len) {
                wsgi_req->write_errors++;
                return -1;
        }
        return uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, lm, len);
}
Esempio n. 10
0
File: writer.c Progetto: JuanS/uwsgi
int uwsgi_response_add_date(struct wsgi_request *wsgi_req, char *hkey, uint16_t hlen, uint64_t t) {
        // 30+1
        char d[31];
        int len = uwsgi_http_date((time_t) t, d);
        if (!len) {
                wsgi_req->write_errors++;
                return -1;
        }
        return uwsgi_response_add_header(wsgi_req, hkey, hlen, d, len);
}
Esempio n. 11
0
int uwsgi_response_add_expires(struct wsgi_request *wsgi_req, uint64_t t) {
	// 30+1
        char expires[31];
	int len = uwsgi_http_date((time_t) t, expires);
	if (!len) {
		wsgi_req->write_errors++;
                return -1;
        }
	return uwsgi_response_add_header(wsgi_req, "Expires", 7, expires, len); 
}
Esempio n. 12
0
File: webdav.c Progetto: JuanS/uwsgi
/*
	OPTIONS: if it is a valid webdav resource add Dav: to the response header	
*/
static int uwsgi_wevdav_manage_options(struct wsgi_request *wsgi_req) {
	uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
	if (udav.add_option) {
		struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size);
		if (uwsgi_buffer_append(ub, "1, 2, 3", 7)) goto end;
		struct uwsgi_string_list *usl = udav.add_option;
		while(usl) {
			if (uwsgi_buffer_append(ub, ", ", 2)) goto end;
			if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end;
			usl = usl->next;
		}
		uwsgi_response_add_header(wsgi_req, "Dav", 3, ub->buf, ub->pos);
end:	
		uwsgi_buffer_destroy(ub);
	}
	else {
		uwsgi_response_add_header(wsgi_req, "Dav", 3, "1, 2, 3", 7);
	}
	return UWSGI_OK;
}
Esempio n. 13
0
int uwsgi_response_add_content_range(struct wsgi_request *wsgi_req, uint64_t start, uint64_t end, uint64_t cl) {
        char buf[6+(sizeof(UMAX64_STR)*3)+4];
	if (end == 0) {
		end = cl-1;
	}
        int ret = snprintf(buf, 6+(sizeof(UMAX64_STR)*3)+4, "bytes %llu-%llu/%llu", (unsigned long long) start, (unsigned long long) end, (unsigned long long) cl);
        if (ret <= 0 || ret > (int) (6+(sizeof(UMAX64_STR)*3)+4)) {
                wsgi_req->write_errors++;
                return -1;
        }
        return uwsgi_response_add_header(wsgi_req, "Content-Range", 13, buf, ret);
}
Esempio n. 14
0
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) {

	size_t mime_type_size = 0;
	char http_last_modified[49];

	if (uwsgi.threads > 1)
		pthread_mutex_lock(&uwsgi.lock_static);

	char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size);

	if (uwsgi.threads > 1)
		pthread_mutex_unlock(&uwsgi.lock_static);

	if (wsgi_req->if_modified_since_len) {
		time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len);
		if (st->st_mtime <= ims) {
			uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16); 
			return uwsgi_response_write_headers_do(wsgi_req);
		}
	}
#ifdef UWSGI_DEBUG
	uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename);
#endif

	size_t fsize = st->st_size;
        if (wsgi_req->range_to) {
        	fsize = wsgi_req->range_to - wsgi_req->range_from;
                if (fsize > (size_t)st->st_size) {
                	fsize = st->st_size;
                }
        }
	else {
        	// reset in case of inconsistent size
        	if (wsgi_req->range_from > fsize) {
        		wsgi_req->range_from = 0;
                	fsize = 0 ;
        	}
		else {
			fsize -= wsgi_req->range_from;
		}
	}

	// HTTP status
	if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
		if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1;
	}
	else {
		if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
	}

#ifdef UWSGI_PCRE
	uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st);
	uwsgi_add_expires_path_info(wsgi_req, st);
	uwsgi_add_expires_uri(wsgi_req, st);
#endif

	// Content-Type (if available)
	if (mime_type_size > 0 && mime_type) {
		if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1;
		// check for content-type related headers
		uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st);
	}

	// increase static requests counter
	uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++;

	// nginx
	if (uwsgi.file_serve_mode == 1) {
		if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1;
		// this is the final header (\r\n added)
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
	}
	// apache
	else if (uwsgi.file_serve_mode == 2) {
		if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1;
		// this is the final header (\r\n added)
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;
	}
	// raw
	else {
		// here we need to choose if we want the gzip variant;
		if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) {
			if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1;
		}
		// set Content-Length (to fsize NOT st->st_size)
		if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1;
		if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) {
			// here use teh original size !!!
			if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1;
		}
		int size = set_http_date(st->st_mtime, http_last_modified);
		if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1;

		// if it is a HEAD request just skip transfer
		if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
			wsgi_req->status = 200;
			return 0;
		}

		// Ok, the file must be transferred from uWSGI
		// offloading will be automatically managed
		int fd = open(real_filename, O_RDONLY);
		if (fd < 0) return -1;
		// fd will be closed in the following function
		uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize);
	}

	wsgi_req->status = 200;
	return 0;
}
Esempio n. 15
0
File: webdav.c Progetto: JuanS/uwsgi
static int uwsgi_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) {
	char filename[PATH_MAX];
	size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename);
	if (!filename_len) {
		uwsgi_404(wsgi_req);
		return UWSGI_OK;
	}

	if (uwsgi_is_dir(filename)) {
		uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
		if (send_body) {
			uwsgi_webdav_dirlist(wsgi_req, filename);
		}
		return UWSGI_OK;
	}

	int fd = open(filename, O_RDONLY);
	if (fd < 0) {
		uwsgi_403(wsgi_req);
		return UWSGI_OK;
	}
	struct stat st;
	if (fstat(fd, &st)) {
		close(fd);
		uwsgi_403(wsgi_req);
		return UWSGI_OK;
	}

	if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6))
		goto end;
	// add content_length
	if (uwsgi_response_add_content_length(wsgi_req, st.st_size))
		goto end;
	// add last-modified
	if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime))
		goto end;
	// add mime_type
	size_t mime_type_len = 0;
	char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len);
	if (mime_type) {
		if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len))
			goto end;
	}
	// add ETag (based on file mtime, not rock-solid, but good enough)
	char *etag = uwsgi_num2str(st.st_mtime);
	if (uwsgi_response_add_header(wsgi_req, "ETag", 4, etag, strlen(etag))) {
		free(etag);
		goto end;
	}
	free(etag);
	// start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations)
	if (!send_body)
		goto end;
	// use a pretty big buffer (for performance reasons)
	char buf[32768];
	size_t remains = st.st_size;
	while (remains > 0) {
		ssize_t rlen = read(fd, buf, UMIN(32768, remains));
		if (rlen <= 0) {
			uwsgi_error("uwsgi_wevdav_manage_get/read()");
			break;
		}
		remains -= rlen;
		if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) {
			break;
		}
	}
end:
	close(fd);
	return UWSGI_OK;
}
Esempio n. 16
0
int uwsgi_jvm_iterator_to_response_headers(struct wsgi_request *wsgi_req, jobject headers) {
        int error = 0;
        while(uwsgi_jvm_iterator_hasNext(headers)) {
                jobject hh = NULL, h_key = NULL, h_value = NULL;

                hh = uwsgi_jvm_iterator_next(headers);

                if (!hh) { error = 1 ; goto clear;}
                h_key = uwsgi_jvm_getKey(hh);
                if (!h_key) { error = 1 ; goto clear;}
                h_value = uwsgi_jvm_getValue(hh);
                if (!h_value) { error = 1 ; goto clear;}


                if (!uwsgi_jvm_object_is_instance(h_key, ujvm.str_class)) {
                        uwsgi_log("headers key must be java/lang/String !!!\n");
                        error = 1 ; goto clear;
                }

                // check for string
                if (uwsgi_jvm_object_is_instance(h_value, ujvm.str_class)) {
                        char *c_h_key = uwsgi_jvm_str2c(h_key);
                        uint16_t c_h_keylen = uwsgi_jvm_strlen(h_key);
                        char *c_h_value = uwsgi_jvm_str2c(h_value);
                        uint16_t c_h_vallen = uwsgi_jvm_strlen(h_value);
                        int ret = uwsgi_response_add_header(wsgi_req, c_h_key, c_h_keylen, c_h_value, c_h_vallen);
                        uwsgi_jvm_release_chars(h_key, c_h_key);
                        uwsgi_jvm_release_chars(h_value, c_h_value);
                        if (ret) error = 1;
                        goto clear;
                }

		// check for string array
		if (uwsgi_jvm_object_is_instance(h_value, ujvm.str_array_class)) {
			size_t items = uwsgi_jvm_array_len(h_value);
			size_t i;
			for(i=0;i<items;i++) {
				jobject hh_value = uwsgi_jvm_array_get(h_value, i);
                                if (!uwsgi_jvm_object_is_instance(hh_value, ujvm.str_class)) {
                                        uwsgi_log("headers value must be java/lang/String !!!\n");
                                        uwsgi_jvm_local_unref(hh_value);
                                        error = 1 ; goto clear;
                                }
                                char *c_h_key = uwsgi_jvm_str2c(h_key);
                                uint16_t c_h_keylen = uwsgi_jvm_strlen(h_key);
                                char *c_h_value = uwsgi_jvm_str2c(hh_value);
                                uint16_t c_h_vallen = uwsgi_jvm_strlen(hh_value);
                                int ret = uwsgi_response_add_header(wsgi_req, c_h_key, c_h_keylen, c_h_value, c_h_vallen);
                                uwsgi_jvm_release_chars(h_key, c_h_key);
                                uwsgi_jvm_release_chars(hh_value, c_h_value);
                                uwsgi_jvm_local_unref(hh_value);
                                if (ret) { error = 1 ; goto clear;}
			}
			goto clear;
		}
		
                // check for iterable
                jobject values = uwsgi_jvm_auto_iterator(h_value);
                if (values) {
                        while(uwsgi_jvm_iterator_hasNext(values)) {
                                jobject hh_value = uwsgi_jvm_iterator_next(values);
                                if (!uwsgi_jvm_object_is_instance(hh_value, ujvm.str_class)) {
                                        uwsgi_log("headers value must be java/lang/String !!!\n");
                                        uwsgi_jvm_local_unref(hh_value);
                                        uwsgi_jvm_local_unref(values);
                                        error = 1 ; goto clear;
                                }
                                char *c_h_key = uwsgi_jvm_str2c(h_key);
                                uint16_t c_h_keylen = uwsgi_jvm_strlen(h_key);
                                char *c_h_value = uwsgi_jvm_str2c(hh_value);
                                uint16_t c_h_vallen = uwsgi_jvm_strlen(hh_value);
                                int ret = uwsgi_response_add_header(wsgi_req, c_h_key, c_h_keylen, c_h_value, c_h_vallen);
                                uwsgi_jvm_release_chars(h_key, c_h_key);
                                uwsgi_jvm_release_chars(hh_value, c_h_value);
                                uwsgi_jvm_local_unref(hh_value);
                                if (ret) { uwsgi_jvm_local_unref(values); error = 1 ; goto clear;}
                        }
                        uwsgi_jvm_local_unref(values);
                        goto clear;
                }
                uwsgi_log("unsupported header value !!! (must be java/lang/String or [java/lang/String)\n");
                error = 1;
clear:
                if (h_value)
                uwsgi_jvm_local_unref(h_value);
                if (h_key)
                uwsgi_jvm_local_unref(h_key);
                if (hh)
                uwsgi_jvm_local_unref(hh);
                if (error) return -1;;
        }
        return 0;
}
Esempio n. 17
0
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) {

	size_t i;
	size_t header_size = 0;
	int status_sent = 0;
	size_t remains = blen;
	char *ptr = buf;
	size_t len = 0;

	while(remains > 0) {
		ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout);
		if (rlen < 0) {
			if (!errno) return 1;
			return -1;
		}
		// timed out
		if (rlen == 0) return -1;
		remains -= rlen;
		len += rlen;
		ptr += rlen;

		// Search for Status/Location headers
		if (!status_sent) {
			status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len); 
			if (status_sent < 0) return -1;
			// need more data ?
			if (status_sent == 0) continue;
		}

		// send headers
		char *key = buf;
		char *value = NULL;

		for(i=0;i<len;i++) {
			// end of a line
			if (buf[i] == '\n') {
				// end of headers
				if (key == NULL) {
					i++;
					goto send_body;
				}
				// invalid header
				else if (value == NULL) {
					return -1;
				}
				header_size = (buf+i) - key;
				// security check
				if (buf+i > buf) {
					if ((buf[i-1]) == '\r') {
						header_size--;
					}
				}

#ifdef UWSGI_DEBUG
				uwsgi_log("found CGI header: %.*s\n", header_size, key);
#endif

				// Ignore "Status: NNN" header
				if (header_size >= 11) {
					if (!strncasecmp("Status: ", key, 8)) {
						key = NULL;
						value = NULL;
						continue;
					}
				}

				uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size);
				key = NULL;
				value = NULL;
			}
			else if (buf[i] == ':') {
				value = buf+i;
			}
			else if (buf[i] != '\r') {
				if (key == NULL) {
					key = buf + i;
				}
			}
		}
	}

	return -1;

send_body:

	if (len-i > 0) {
		uwsgi_response_write_body_do(wsgi_req, buf+i, len-i);
	}

	return 0;	
}
Esempio n. 18
0
int uwsgi_response_subhandler_pump(struct wsgi_request *wsgi_req) {

	PyObject *pychunk;
	int i;

	char sc[4];

	// ok its a yield
	if (!wsgi_req->async_placeholder) {
		if (PyDict_Check((PyObject *)wsgi_req->async_result)) {


			PyObject *status = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "status");
			if (!status) {
				uwsgi_log("invalid Pump response (status code).\n"); 
				goto clear; 
			}

			PyObject *headers = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "headers");
			if (!headers) {
				uwsgi_log("invalid Pump response (headers).\n"); 
				goto clear; 
			}


			wsgi_req->async_placeholder =  PyDict_GetItemString((PyObject *)wsgi_req->async_result, "body");
			if (!wsgi_req->async_placeholder) {
				uwsgi_log("invalid Pump response (body).\n"); 
				goto clear; 
			}

			// get the status code
			if (!PyInt_Check(status)) {
				uwsgi_log("invalid Pump response (status code).\n"); 
				goto clear; 
			}

			if (uwsgi_num2str2n(PyInt_AsLong(status), sc, 4) != 3) {
				uwsgi_log("invalid Pump response (status code).\n"); 
				goto clear; 
			}

			if (uwsgi_response_prepare_headers(wsgi_req, sc, 3)) {
				uwsgi_log("unable to prepare response headers\n");
			}

			PyObject *hhkey, *hhvalue;
#ifdef UWSGI_PYTHON_OLD
			int hhpos = 0;
#else
			Py_ssize_t hhpos = 0;
#endif
			while (PyDict_Next(headers, &hhpos, &hhkey, &hhvalue)) {
				if (!PyString_Check(hhkey)) continue;

				char *k = PyString_AsString(hhkey);
				size_t kl = PyString_Size(hhkey);	
				k[0] = toupper((int) k[0]);

				if (PyList_Check(hhvalue)) {
					for(i=0;i<PyList_Size(hhvalue);i++) {
						PyObject *item = PyList_GetItem(hhvalue, i);
						if (PyString_Check(item)) {
							if (uwsgi_response_add_header(wsgi_req, k, kl, PyString_AsString(item), PyString_Size(item))) goto clear;
						}
					}	
				}
				else if (PyString_Check(hhvalue)) {
					if (uwsgi_response_add_header(wsgi_req, k, kl, PyString_AsString(hhvalue), PyString_Size(hhvalue))) goto clear;
				}
			}

			Py_INCREF((PyObject *)wsgi_req->async_placeholder);

			if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) {
				UWSGI_RELEASE_GIL
				uwsgi_response_write_body_do(wsgi_req, PyString_AsString(wsgi_req->async_placeholder), PyString_Size(wsgi_req->async_placeholder));
				UWSGI_GET_GIL
				uwsgi_py_check_write_errors {
                                        uwsgi_py_write_exception(wsgi_req);
                                }
                		goto clear;
        		}
#ifdef PYTHREE
			else if ((wsgi_req->sendfile_fd = PyObject_AsFileDescriptor((PyObject *)wsgi_req->async_placeholder)) > -1) {
Esempio n. 19
0
static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {

	int i;
	const char *http, *http2;
	size_t slen, slen2;
	char *ptrbuf;
	lua_State *L = ulua.L[wsgi_req->async_id];

	if (wsgi_req->async_status == UWSGI_AGAIN) {
		if ((i = lua_pcall(L, 0, 1, 0)) == 0) {
			if (lua_type(L, -1) == LUA_TSTRING) {
				http = lua_tolstring(L, -1, &slen);
				uwsgi_response_write_body_do(wsgi_req, (char *)http, slen);
			}
			lua_pop(L, 1);
			lua_pushvalue(L, -1);
			return UWSGI_AGAIN;
		}
		goto clear;
	}

	/* Standard WSAPI request */
	if (!wsgi_req->uh->pktsize) {
		uwsgi_log( "Empty lua request. skip.\n");
		return -1;
	}

	if (uwsgi_parse_vars(wsgi_req)) {
		return -1;
	}

	// put function in the stack
	//lua_getfield(L, LUA_GLOBALSINDEX, "run");
	lua_pushvalue(L, -1);

	// put cgi vars in the stack

	lua_newtable(L);
	lua_pushstring(L, "");
	lua_setfield(L, -2, "CONTENT_TYPE");
	for(i=0;i<wsgi_req->var_cnt;i++) {
		lua_pushlstring(L, (char *)wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len);
		// transform it in a valid c string TODO this is ugly
		ptrbuf = wsgi_req->hvec[i].iov_base+wsgi_req->hvec[i].iov_len;
		*ptrbuf = 0;
		lua_setfield(L, -2, (char *)wsgi_req->hvec[i].iov_base);
		i++;
	}


	// put "input" table
	lua_newtable(L);
	lua_pushcfunction(L, uwsgi_lua_input);
	lua_setfield(L, -2, "read");
	lua_setfield(L, -2, "input");

#ifdef UWSGI_DEBUG
	uwsgi_log("stack pos %d\n", lua_gettop(L));
#endif

	// call function
	i = lua_pcall(L, 1, 3, 0);
	if (i != 0) {
		uwsgi_log("%s\n", lua_tostring(L, -1));
		lua_pop(L, 1);
                lua_pushvalue(L, -1);
		goto clear;
	}

	//uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) ,  lua_typename(L, lua_type(L, -1)));

	// send status
	if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) {
		http = lua_tolstring(L, -3, &slen);
		uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen);
	}
	else {
		uwsgi_log("[uwsgi-lua] invalid response status !!!\n");
		// let's continue 
	}

	// send headers

	lua_pushnil(L);
	while(lua_next(L, -3) != 0) {
		http = lua_tolstring(L, -2, &slen);
		http2 = lua_tolstring(L, -1, &slen2);
		uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2);
		lua_pop(L, 1);
	}

	// send body with coroutine
	lua_pushvalue(L, -1);

	while ( (i = lua_pcall(L, 0, 1, 0)) == 0) {
		if (lua_type(L, -1) == LUA_TSTRING) {
			http = lua_tolstring(L, -1, &slen);
			uwsgi_response_write_body_do(wsgi_req, (char *)http, slen);
		}
		lua_pop(L, 1);
		lua_pushvalue(L, -1);
		if (uwsgi.async > 1) {
			return UWSGI_AGAIN;
		}
	}

clear:
	lua_pop(L, 4);
	// set frequency
	lua_gc(L, LUA_GCCOLLECT, 0);

	return UWSGI_OK;

}
Esempio n. 20
0
File: rados.c Progetto: Nikolo/uwsgi
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) {
	char filename[PATH_MAX+1];
	if (!wsgi_req->len) {
		uwsgi_log( "Empty request. skip.\n");
		return -1;
	}

	if (uwsgi_parse_vars(wsgi_req)) {
		return -1;
	}

	// blocks empty paths
	if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) {
		uwsgi_403(wsgi_req);
		return UWSGI_OK;
	}

	wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1);
	if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
		if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) {
			wsgi_req->app_id = uwsgi.default_app;
		}
	}
	if (wsgi_req->app_id == -1) {
		uwsgi_404(wsgi_req);
		return UWSGI_OK;
	}

	struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];

	if (wsgi_req->path_info_len > ua->mountpoint_len &&
		memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) {

		memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len);
		filename[wsgi_req->path_info_len-ua->mountpoint_len] = 0;

	} else {
		memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len);
		filename[wsgi_req->path_info_len] = 0;
	}
	
	// in multithread mode the memory is different (as we need a ctx for each thread) !!!
	rados_ioctx_t ctx;
	if (uwsgi.threads > 1) {
		rados_ioctx_t *ctxes = (rados_ioctx_t *) ua->responder0;
		ctx = ctxes[wsgi_req->async_id];
	}
	else {
		ctx = (rados_ioctx_t) ua->responder0;
	}
	struct uwsgi_rados_mountpoint *urmp = (struct uwsgi_rados_mountpoint *) ua->responder1;
	uint64_t stat_size = 0;
	time_t stat_mtime = 0;

	struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id];

	if (uwsgi.async > 0) {
	// no need to lock here (the rid protect us)
        	if (pipe(urio->fds)) {
                	uwsgi_error("uwsgi_rados_read_async()/pipe()");
			uwsgi_500(wsgi_req);
			return UWSGI_OK;
        	}
	}
	
	int ret = -1;
	int timeout = urmp->timeout ? urmp->timeout : urados.timeout;

	if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) {
		if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end;
		if (uwsgi_response_add_header(wsgi_req, "Dav", 3, "1", 1)) goto end;	
		struct uwsgi_buffer *ub_allow = uwsgi_buffer_new(64);
		if (uwsgi_buffer_append(ub_allow, "OPTIONS, GET, HEAD", 18)) {
			uwsgi_buffer_destroy(ub_allow);
			goto end;
		}
		if (urmp->allow_put) {
			if (uwsgi_buffer_append(ub_allow, ", PUT", 5)) {
				uwsgi_buffer_destroy(ub_allow);
				goto end;
			}
		}
		if (urmp->allow_delete) {
			if (uwsgi_buffer_append(ub_allow, ", DELETE", 8)) {
				uwsgi_buffer_destroy(ub_allow);
				goto end;
			}
		}
		if (urmp->allow_mkcol) {
			if (uwsgi_buffer_append(ub_allow, ", MKCOL", 7)) {
				uwsgi_buffer_destroy(ub_allow);
				goto end;
			}
		}
		if (urmp->allow_propfind) {
			if (uwsgi_buffer_append(ub_allow, ", PROPFIND", 10)) {
				uwsgi_buffer_destroy(ub_allow);
				goto end;
			}
		}

		uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos);
		uwsgi_buffer_destroy(ub_allow);
                goto end;
	}

	// empty paths are mapped to propfind
	if (wsgi_req->path_info_len == 1 && wsgi_req->path_info[0] == '/') {
		if (urmp->allow_propfind && !uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
			uwsgi_rados_propfind(wsgi_req, ctx, NULL, 0, 0, timeout);
			goto end;
		}
                uwsgi_405(wsgi_req);
		goto end;
	}

	// MKCOL does not require stat
	if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) {
                if (!urmp->allow_mkcol) {
                        uwsgi_405(wsgi_req);
                        goto end;
                }
                ret = rados_pool_create(urmp->cluster, filename);
		if (ret < 0) {
			if (ret == -EEXIST) {
                        	uwsgi_405(wsgi_req);
			}
			else {
                        	uwsgi_500(wsgi_req);
			}
                        goto end;
                }
                uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);
                goto end;
	}

	if (uwsgi.async > 0) {
		ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout);	
	}
	else {
		ret = rados_stat(ctx, filename, &stat_size, &stat_mtime);
	}

	// PUT AND MKCOL can be used for non-existent objects
	if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) {
		if (!urmp->allow_put) {
			uwsgi_405(wsgi_req);
			goto end;
		}
		if (ret == 0) {
			if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) {
				uwsgi_500(wsgi_req);
				goto end;
			}
		}	
		if (uwsgi_rados_put(wsgi_req, ctx, filename, urmp->put_buffer_size, timeout)) {
			uwsgi_500(wsgi_req);
			goto end;
		}
		uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11);	
		goto end;
	}
	else if (ret < 0) {
		if (ret == -ENOENT)
			uwsgi_404(wsgi_req);
		else
			uwsgi_403(wsgi_req);
		goto end;
	}

	if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) {
		if (!urmp->allow_delete) {
			uwsgi_405(wsgi_req);
                        goto end;
		}
		if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) {
			uwsgi_403(wsgi_req);
                        goto end;
		}
		uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6);
		goto end;
	}

	if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) {
		if (!urmp->allow_propfind) {
			uwsgi_405(wsgi_req);
                        goto end;
		}
		uwsgi_rados_propfind(wsgi_req, ctx, filename, stat_size, stat_mtime, timeout);
		goto end;
	}

	if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) {
		uwsgi_405(wsgi_req);
		goto end;
	}

	uint64_t offset = 0;
	uint64_t remains = stat_size;
	uwsgi_request_fix_range_for_size(wsgi_req, remains);
	switch (wsgi_req->range_parsed) {
		case UWSGI_RANGE_INVALID:
			if (uwsgi_response_prepare_headers(wsgi_req,
						"416 Requested Range Not Satisfiable", 35))
				goto end;
			if (uwsgi_response_add_content_range(wsgi_req, -1, -1, stat_size))
				goto end;
			return 0;
		case UWSGI_RANGE_VALID:
			offset = wsgi_req->range_from;
			remains = wsgi_req->range_to - wsgi_req->range_from + 1;
			if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19))
				goto end;
			break;
		default: /* UWSGI_RANGE_NOT_PARSED */
			if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1;
	}

	size_t mime_type_len = 0;
	char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len);
	if (mime_type) {
		if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end;
	}

	if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) stat_mtime)) goto end;
        // set Content-Length to actual result size
	if (uwsgi_response_add_content_length(wsgi_req, remains)) goto end;
        if (wsgi_req->range_parsed == UWSGI_RANGE_VALID) {
                // here use the original size !!!
                if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, stat_size))
                        goto end;
        }

	// skip body on HEAD
	if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) {
		if (uwsgi.async > 0) {
			if (uwsgi_rados_read_async(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size, timeout)) goto end;
		}
		else {
			if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size)) goto end;
		}
	}

end:
	if (uwsgi.async > 0) {
		close(urio->fds[0]);
		close(urio->fds[1]);
	}
	return UWSGI_OK;
}
Esempio n. 21
0
PyObject *py_uwsgi_spit(PyObject * self, PyObject * args) {
    PyObject *headers, *head;
    PyObject *h_key, *h_value;
    PyObject *exc_info = NULL;
    size_t i;

    struct wsgi_request *wsgi_req = py_current_wsgi_req();

    // avoid double sending of headers
    if (wsgi_req->headers_sent) {
        return PyErr_Format(PyExc_IOError, "headers already sent");
    }

    // this must be done before headers management
    if (PyTuple_Size(args) > 2) {
        exc_info = PyTuple_GetItem(args, 2);
        if (exc_info && exc_info != Py_None) {
            PyObject *exc_type = PyTuple_GetItem(exc_info, 0);
            PyObject *exc_val = PyTuple_GetItem(exc_info, 1);
            PyObject *exc_tb = PyTuple_GetItem(exc_info, 2);

            if (!exc_type || !exc_val || !exc_tb) {
                return NULL;
            }

            Py_INCREF(exc_type);
            Py_INCREF(exc_val);
            Py_INCREF(exc_tb);
            // in this way, error will be reported to the log
            PyErr_Restore(exc_type, exc_val, exc_tb);

            // the error is reported, let's continue...
            // return NULL
        }
    }

    head = PyTuple_GetItem(args, 0);
    if (!head) {
        return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
    }

#ifdef PYTHREE
    // check for web3
    if ((self != Py_None && !PyUnicode_Check(head)) || (self == Py_None && !PyBytes_Check(head))) {
#else
    if (!PyString_Check(head)) {
#endif
        return PyErr_Format(PyExc_TypeError, "http status must be a string");
    }

    char *status_line = NULL;
    size_t status_line_len = 0;
#ifdef PYTHREE
    PyObject *zero = NULL;
    PyObject *zero2 = NULL;
    if (self != Py_None) {
        zero = PyUnicode_AsASCIIString(head);
        if (!zero) {
            return PyErr_Format(PyExc_TypeError, "http status string must be encodable in latin1");
        }
        status_line = PyBytes_AsString(zero);
        status_line_len = PyBytes_Size(zero);
    }
    else {
        status_line = PyBytes_AsString(head);
        status_line_len = PyBytes_Size(head);
    }
#else
    status_line = PyString_AsString(head);
    status_line_len = PyString_Size(head);
#endif
    if (uwsgi_response_prepare_headers(wsgi_req, status_line, status_line_len)) {
#ifdef PYTHREE
        Py_DECREF(zero);
#endif
        goto end;
    }

#ifdef PYTHREE
    Py_DECREF(zero);
#endif

    headers = PyTuple_GetItem(args, 1);
    if (!headers) {
        return PyErr_Format(PyExc_TypeError, "start_response() takes at least 2 arguments");
    }

    if (!PyList_Check(headers)) {
        return PyErr_Format(PyExc_TypeError, "http headers must be in a python list");
    }

    size_t h_count = PyList_Size(headers);

    for (i = 0; i < h_count; i++) {
        head = PyList_GetItem(headers, i);
        if (!head) {
            return NULL;
        }
        if (!PyTuple_Check(head)) {
            return PyErr_Format(PyExc_TypeError, "http header must be defined in a tuple");
        }
        h_key = PyTuple_GetItem(head, 0);
        if (!h_key) {
            return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
        }
#ifdef PYTHREE
        if ((self != Py_None && !PyUnicode_Check(h_key)) || (self == Py_None && !PyBytes_Check(h_key))) {
#else
        if (!PyString_Check(h_key)) {
#endif
            return PyErr_Format(PyExc_TypeError, "http header key must be a string");
        }
        h_value = PyTuple_GetItem(head, 1);
        if (!h_value) {
            return PyErr_Format(PyExc_TypeError, "http header must be a 2-item tuple");
        }
#ifdef PYTHREE
        if ((self != Py_None && !PyUnicode_Check(h_value)) || (self == Py_None && !PyBytes_Check(h_value))) {
#else
        if (!PyString_Check(h_value)) {
#endif
            return PyErr_Format(PyExc_TypeError, "http header value must be a string");
        }


        char *k = NULL;
        size_t kl = 0;
        char *v = NULL;
        size_t vl = 0;

#ifdef PYTHREE
        if (self != Py_None) {
            zero = PyUnicode_AsASCIIString(h_key);
            if (!zero) {
                return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
            }
            k = PyBytes_AsString(zero);
            kl = PyBytes_Size(zero);
        }
        else {
            k = PyBytes_AsString(h_key);
            kl = PyBytes_Size(h_key);
        }
#else
        k = PyString_AsString(h_key);
        kl = PyString_Size(h_key);
#endif

#ifdef PYTHREE
        if (self != Py_None) {
            zero2 = PyUnicode_AsASCIIString(h_value);
            if (!zero2) {
                return PyErr_Format(PyExc_TypeError, "http header must be encodable in latin1");
            }
            v = PyBytes_AsString(zero2);
            vl = PyBytes_Size(zero2);
        }
        else {
            v = PyBytes_AsString(h_value);
            vl = PyBytes_Size(h_value);
        }
#else
        v = PyString_AsString(h_value);
        vl = PyString_Size(h_value);
#endif

        if (uwsgi_response_add_header(wsgi_req, k, kl, v, vl)) {
#ifdef PYTHREE
            Py_DECREF(zero);
            Py_DECREF(zero2);
#endif
            return PyErr_Format(PyExc_TypeError, "unable to add header to the response");
        }

#ifdef PYTHREE
        Py_DECREF(zero);
        Py_DECREF(zero2);
#endif

    }

    if (up.start_response_nodelay) {
        UWSGI_RELEASE_GIL
        if (uwsgi_response_write_headers_do(wsgi_req)) {
            UWSGI_GET_GIL
            return PyErr_Format(PyExc_IOError, "unable to directly send headers");
        }
        UWSGI_GET_GIL
    }

end:
    Py_INCREF(up.wsgi_writeout);
    return up.wsgi_writeout;
}