static void check_response_header(liStreamHttpResponse* shr) { liResponse *resp = &shr->vr->response; GList *l; shr->transfer_encoding_chunked = FALSE; /* Transfer-Encoding: chunked */ l = li_http_header_find_first(resp->headers, CONST_STR_LEN("transfer-encoding")); if (l) { for ( ; l ; l = li_http_header_find_next(l, CONST_STR_LEN("transfer-encoding")) ) { liHttpHeader *hh = (liHttpHeader*) l->data; if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "identity" )) { /* ignore */ continue; } if (0 == g_ascii_strcasecmp( LI_HEADER_VALUE(hh), "chunked" )) { if (shr->transfer_encoding_chunked) { VR_ERROR(shr->vr, "%s", "Response is chunked encoded twice"); li_vrequest_error(shr->vr); return; } shr->transfer_encoding_chunked = TRUE; } else { VR_ERROR(shr->vr, "Response has unsupported Transfer-Encoding: %s", LI_HEADER_VALUE(hh)); li_vrequest_error(shr->vr); return; } } li_http_header_remove(resp->headers, CONST_STR_LEN("transfer-encoding")); /* any non trivial transfer-encoding overwrites content-length */ if (shr->transfer_encoding_chunked) { li_http_header_remove(resp->headers, CONST_STR_LEN("content-length")); } } /* Upgrade: */ l = li_http_header_find_first(resp->headers, CONST_STR_LEN("upgrade")); if (l) { gboolean have_connection_upgrade = FALSE; liHttpHeaderTokenizer header_tokenizer; GString *token; if (101 != resp->http_status) { VR_ERROR(shr->vr, "Upgrade but status is %i instead of 101 'Switching Protocols'", resp->http_status); li_vrequest_error(shr->vr); return; } if (shr->transfer_encoding_chunked) { VR_ERROR(shr->vr, "%s", "Upgrade with Transfer-Encoding: chunked"); li_vrequest_error(shr->vr); return; } /* requires Connection: Upgrade header */ token = g_string_sized_new(15); li_http_header_tokenizer_start(&header_tokenizer, resp->headers, CONST_STR_LEN("Connection")); while (li_http_header_tokenizer_next(&header_tokenizer, token)) { VR_ERROR(shr->vr, "Parsing header '%s'", ((liHttpHeader*)header_tokenizer.cur->data)->data->str); VR_ERROR(shr->vr, "Connection token '%s'", token->str); if (0 == g_ascii_strcasecmp(token->str, "Upgrade")) { have_connection_upgrade = TRUE; break; } } g_string_free(token, TRUE); token = NULL; if (!have_connection_upgrade) { VR_ERROR(shr->vr, "%s", "Upgrade without Connection: Upgrade Transfer"); li_vrequest_error(shr->vr); return; } shr->response_headers_finished = TRUE; shr->vr->backend_drain->out->is_closed = FALSE; { /* li_vrequest_connection_upgrade releases vr->backend_drain; keep our own reference */ liStream *backend_drain = shr->vr->backend_drain; shr->vr->backend_drain = NULL; li_vrequest_connection_upgrade(shr->vr, backend_drain, &shr->stream); li_stream_release(backend_drain); } return; } shr->response_headers_finished = TRUE; li_vrequest_indirect_headers_ready(shr->vr); return; }
void li_response_send_error_page(liConnection *con) { liVRequest *vr = con->mainvr; gchar status_code[3]; guint len; gchar *str; GString *html; html = g_string_sized_new(1023); g_string_append_len(html, CONST_STR_LEN( "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n" "<html>\n" " <head>\n" " <title>" )); li_http_status_to_str(con->mainvr->response.http_status, status_code); g_string_append_len(html, status_code, 3); g_string_append_len(html, CONST_STR_LEN(" - ")); str = li_http_status_string(con->mainvr->response.http_status, &len); g_string_append_len(html, str, len); g_string_append_len(html, CONST_STR_LEN( "</title>\n" " <style type=\"text/css\">\n" " body { font-size: 62.5%; }\n" " #container {\n" " font-size: 62.5%;\n" " max-width: 600px;\n" " margin: auto;\n" " margin-top: 2%;\n" " border: 4px solid #efefef;\n" " padding: 0px 20px;\n" " color: #444;\n" " font-family: Verdana,helvetica,sans-serif;\n" " font-size: 1.25em;\n" " }\n" " h1 { color: #6D84B4; font-size: 1.5em; }\n" " #footer { text-align: right; margin-top: 25px; }\n" " </style>\n" " </head>\n" " <body>\n" " <div id=\"container\">\n" " <h1>Error " )); g_string_append_len(html, status_code, 3); g_string_append_len(html, CONST_STR_LEN(" - ")); g_string_append_len(html, str, len); g_string_append_len(html, CONST_STR_LEN("</h1>\n")); str = li_response_error_description(con->mainvr->response.http_status, &len); g_string_append_len(html, str, len); g_string_append_len(html, CONST_STR_LEN(" <p id=\"footer\">")); g_string_append_len(html, GSTR_LEN(CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string)); g_string_append_len(html, CONST_STR_LEN( "</p>\n" " </div>\n" " </body>\n" "</html>\n" )); li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html; charset=utf-8")); li_chunkqueue_append_string(con->out, html); li_http_header_remove(vr->response.headers, CONST_STR_LEN("transfer-encoding")); li_http_header_remove(vr->response.headers, CONST_STR_LEN("content-encoding")); li_http_header_remove(vr->response.headers, CONST_STR_LEN("etag")); }