GString *li_mimetype_get(liVRequest *vr, GString *filename) { /* search in mime_types option for the longest suffix match */ GString *mimetype; liMimetypeNode *node; guchar *c, *s; gpointer ptr; if (!vr || !filename || !filename->len) return NULL; node = CORE_OPTIONPTR(LI_CORE_OPTION_MIME_TYPES).ptr; mimetype = node->mimetype; for (s = (guchar*) filename->str, c = (guchar*) filename->str + filename->len; c-- > s; ) { if (*c < node->cmin || *c > node->cmax) return mimetype; ptr = node->children[*c - node->cmin]; if (NULL == ptr) { return mimetype; } if (!MIME_IS_NODE(ptr)) { return ptr; } node = MIME_UNMARK_NODE(ptr); if (NULL != node->mimetype) { mimetype = node->mimetype; } } return mimetype; }
static liHandlerResult dirlist(liVRequest *vr, gpointer param, gpointer *context) { GString *listing; liStatCacheEntry *sce; dirlist_data *dd; UNUSED(context); switch (vr->request.http_method) { case LI_HTTP_METHOD_GET: case LI_HTTP_METHOD_HEAD: break; default: return LI_HANDLER_GO_ON; } if (li_vrequest_is_handled(vr)) return LI_HANDLER_GO_ON; if (vr->physical.path->len == 0) return LI_HANDLER_GO_ON; switch (li_stat_cache_get_dirlist(vr, vr->physical.path, &sce)) { case LI_HANDLER_GO_ON: break; case LI_HANDLER_WAIT_FOR_EVENT: return LI_HANDLER_WAIT_FOR_EVENT; default: return LI_HANDLER_ERROR; } dd = param; if (sce->data.failed) { /* stat failed */ int e = sce->data.err; li_stat_cache_entry_release(vr, sce); switch (e) { case ENOENT: case ENOTDIR: return LI_HANDLER_GO_ON; case EACCES: if (!li_vrequest_handle_direct(vr)) return LI_HANDLER_ERROR; vr->response.http_status = 403; return LI_HANDLER_GO_ON; default: VR_ERROR(vr, "stat('%s') failed: %s", sce->data.path->str, g_strerror(sce->data.err)); return LI_HANDLER_ERROR; } } else if (!S_ISDIR(sce->data.st.st_mode)) { li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; } else if (vr->request.uri.path->len == 0 || vr->request.uri.path->str[vr->request.uri.path->len-1] != '/') { li_stat_cache_entry_release(vr, sce); li_vrequest_redirect_directory(vr); return LI_HANDLER_GO_ON; } else { /* everything ok, we have the directory listing */ gboolean cachable; guint i, j; liStatCacheEntryData *sced; GString *mime_str, *encoded; GArray *directories, *files; gchar sizebuf[sizeof("999.9K")+1]; gchar datebuf[sizeof("2005-Jan-01 22:23:24")+1]; guint datebuflen; struct tm tm; gboolean hide; if (!li_vrequest_handle_direct(vr)) { li_stat_cache_entry_release(vr, sce); return LI_HANDLER_ERROR; } vr->response.http_status = 200; if (dd->debug) VR_DEBUG(vr, "dirlist for \"%s\", %u entries", sce->data.path->str, sce->dirlist->len); li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Type"), GSTR_LEN(dd->content_type)); li_etag_set_header(vr, &sce->data.st, &cachable); if (cachable) { vr->response.http_status = 304; li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; } /* temporary string for encoded names */ encoded = g_string_sized_new(64-1); /* seperate directories from other files */ directories = g_array_sized_new(FALSE, FALSE, sizeof(guint), 16); files = g_array_sized_new(FALSE, FALSE, sizeof(guint), sce->dirlist->len); for (i = 0; i < sce->dirlist->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, i); hide = FALSE; /* ingore entries where the stat() failed */ if (sced->failed) continue; if (dd->hide_dotfiles && sced->path->str[0] == '.') continue; if (dd->hide_tildefiles && sced->path->str[sced->path->len-1] == '~') continue; for (j = 0; j < dd->exclude_suffix->len; j++) { if (li_string_suffix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_suffix, j)))) { hide = TRUE; break; } } if (hide) continue; for (j = 0; j < dd->exclude_prefix->len; j++) { if (li_string_prefix(sced->path, GSTR_LEN((GString*)g_ptr_array_index(dd->exclude_prefix, j)))) { hide = TRUE; break; } } if (hide) continue; if (S_ISDIR(sced->st.st_mode)) { if (dd->hide_directories) continue; g_array_append_val(directories, i); } else { if ((dd->include_header || dd->hide_header) && g_str_equal(sced->path, "HEADER.txt")) { if (dd->hide_header) continue; } else if ((dd->include_readme || dd->hide_readme) && g_str_equal(sced->path, "README.txt")) { if (dd->hide_readme) continue; } g_array_append_val(files, i); } } listing = g_string_sized_new(4*1024-1); g_string_append_printf(listing, html_header_start, vr->request.uri.path->str); if (dd->css) { /* custom css */ g_string_append_len(listing, CONST_STR_LEN(" <link rel=\"stylesheet\" type=\"text/css\" href=\"")); g_string_append_len(listing, GSTR_LEN(dd->css)); g_string_append_len(listing, CONST_STR_LEN("\" />\n")); } else { /* default css */ g_string_append_len(listing, CONST_STR_LEN(html_css)); } g_string_append_len(listing, CONST_STR_LEN(html_header_end)); try_append_file(vr, &listing, "HEADER.txt", dd->encode_header); g_string_append_printf(listing, html_table_start, vr->request.uri.path->str); if (0 != strcmp("/", vr->request.uri.path->str)) { g_string_append_printf(listing, html_table_row, '0', "../", "Parent Directory", (gint64)0, "", (gint64)0, "-", "Directory"); } /* list directories */ if (!dd->hide_directories) { for (i = 0; i < directories->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(directories, guint, i)); localtime_r(&(sced->st.st_mtime), &tm); datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); datebuf[datebuflen] = '\0'; g_string_append_len(listing, CONST_STR_LEN(" <tr group=\"1\"><td><a href=\"")); li_string_encode(sced->path->str, encoded, LI_ENCODING_URI); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("/\">")); li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("</a></td><td class=\"modified\" val=\"")); li_string_append_int(listing, sced->st.st_mtime); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append_len(listing, datebuf, datebuflen); g_string_append_len(listing, CONST_STR_LEN("</td>" "<td class=\"size\" val=\"0\">-</td>" "<td class=\"type\">Directory</td></tr>\n")); } } /*g_string_append_len(listing, CONST_STR_LEN("<tr><td colspan=\"4\"> </td></tr>\n"));*/ /* list files */ for (i = 0; i < files->len; i++) { sced = &g_array_index(sce->dirlist, liStatCacheEntryData, g_array_index(files, guint, i)); mime_str = li_mimetype_get(vr, sced->path); localtime_r(&(sced->st.st_mtime), &tm); datebuflen = strftime(datebuf, sizeof(datebuf), "%Y-%b-%d %H:%M:%S", &tm); datebuf[datebuflen] = '\0'; dirlist_format_size(sizebuf, sced->st.st_size); g_string_append_len(listing, CONST_STR_LEN(" <tr group=\"2\"><td><a href=\"")); li_string_encode(sced->path->str, encoded, LI_ENCODING_URI); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN("\">")); li_string_encode(sced->path->str, encoded, LI_ENCODING_HTML); g_string_append_len(listing, GSTR_LEN(encoded)); g_string_append_len(listing, CONST_STR_LEN( "</a></td>" "<td class=\"modified\" val=\"")); li_string_append_int(listing, sced->st.st_mtime); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append_len(listing, datebuf, datebuflen); g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"size\" val=\"")); li_string_append_int(listing, sced->st.st_size); g_string_append_len(listing, CONST_STR_LEN("\">")); g_string_append(listing, sizebuf); g_string_append_len(listing, CONST_STR_LEN("</td><td class=\"type\">")); if (mime_str) { g_string_append_len(listing, GSTR_LEN(mime_str)); } else { g_string_append_len(listing, CONST_STR_LEN("application/octet-stream")); } g_string_append_len(listing, CONST_STR_LEN("</td></tr>\n")); /* g_string_append_printf(listing, html_table_row, sced->path->str, sced->path->str, (gint64)sced->st.st_mtime, datebuf, sced->st.st_size, sizebuf, mime_str ? mime_str->str : "application/octet-stream"); */ } g_string_append_len(listing, CONST_STR_LEN(html_table_end)); try_append_file(vr, &listing, "README.txt", dd->encode_readme); if (dd->include_sort) { g_string_append_len(listing, CONST_STR_LEN(javascript_sort)); } g_string_append_printf(listing, html_footer, CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string->str); li_chunkqueue_append_string(vr->direct_out, listing); g_string_free(encoded, TRUE); g_array_free(directories, TRUE); g_array_free(files, TRUE); } li_stat_cache_entry_release(vr, sce); return LI_HANDLER_GO_ON; }
static GString *al_format_log(liVRequest *vr, al_data *ald, GArray *format) { GString *str = g_string_sized_new(255); liResponse *resp = &vr->response; liRequest *req = &vr->request; liPhysical *phys = &vr->physical; for (guint i = 0; i < format->len; i++) { GString *tmp_gstr2 = NULL; gchar *tmp_str = NULL; guint len = 0; al_format_entry *e = &g_array_index(format, al_format_entry, i); if (e->type == AL_ENTRY_FORMAT) { switch (e->format.type) { case AL_FORMAT_PERCENT: g_string_append_c(str, '%'); break; case AL_FORMAT_REMOTE_ADDR: g_string_append_len(str, GSTR_LEN(vr->coninfo->remote_addr_str)); break; case AL_FORMAT_LOCAL_ADDR: g_string_append_len(str, GSTR_LEN(vr->coninfo->local_addr_str)); break; case AL_FORMAT_BYTES_RESPONSE: li_string_append_int(str, vr->vr_out->bytes_out); break; case AL_FORMAT_BYTES_RESPONSE_CLF: if (vr->vr_out->bytes_out) li_string_append_int(str, vr->vr_out->bytes_out); else g_string_append_c(str, '-'); break; case AL_FORMAT_DURATION_MICROSECONDS: li_string_append_int(str, (CUR_TS(vr->wrk) - vr->ts_started) * 1000 * 1000); break; case AL_FORMAT_ENV: tmp_gstr2 = li_environment_get(&vr->env, GSTR_LEN(e->key)); if (tmp_gstr2) al_append_escaped(str, tmp_gstr2); else g_string_append_c(str, '-'); break; case AL_FORMAT_FILENAME: if (phys->path->len) g_string_append_len(str, GSTR_LEN(phys->path)); else g_string_append_c(str, '-'); break; case AL_FORMAT_REQUEST_HEADER: li_http_header_get_all(vr->wrk->tmp_str, req->headers, GSTR_LEN(e->key)); if (vr->wrk->tmp_str->len) al_append_escaped(str, vr->wrk->tmp_str); else g_string_append_c(str, '-'); break; case AL_FORMAT_METHOD: g_string_append_len(str, GSTR_LEN(req->http_method_str)); break; case AL_FORMAT_RESPONSE_HEADER: li_http_header_get_all(vr->wrk->tmp_str, resp->headers, GSTR_LEN(e->key)); if (vr->wrk->tmp_str->len) al_append_escaped(str, vr->wrk->tmp_str); else g_string_append_c(str, '-'); break; case AL_FORMAT_LOCAL_PORT: switch (vr->coninfo->local_addr.addr->plain.sa_family) { case AF_INET: li_string_append_int(str, ntohs(vr->coninfo->local_addr.addr->ipv4.sin_port)); break; #ifdef HAVE_IPV6 case AF_INET6: li_string_append_int(str, ntohs(vr->coninfo->local_addr.addr->ipv6.sin6_port)); break; #endif default: g_string_append_c(str, '-'); break; } break; case AL_FORMAT_QUERY_STRING: if (req->uri.query->len) al_append_escaped(str, req->uri.query); else g_string_append_c(str, '-'); break; case AL_FORMAT_FIRST_LINE: g_string_append_len(str, GSTR_LEN(req->http_method_str)); g_string_append_c(str, ' '); al_append_escaped(str, req->uri.raw_orig_path); g_string_append_c(str, ' '); tmp_str = li_http_version_string(req->http_version, &len); g_string_append_len(str, tmp_str, len); break; case AL_FORMAT_STATUS_CODE: li_string_append_int(str, resp->http_status); break; case AL_FORMAT_TIME: /* todo: implement format string */ tmp_gstr2 = li_worker_current_timestamp(vr->wrk, LI_LOCALTIME, ald->ts_ndx); g_string_append_len(str, GSTR_LEN(tmp_gstr2)); break; case AL_FORMAT_DURATION_SECONDS: li_string_append_int(str, CUR_TS(vr->wrk) - vr->ts_started); break; case AL_FORMAT_AUTHED_USER: tmp_gstr2 = li_environment_get(&vr->env, CONST_STR_LEN("REMOTE_USER")); if (tmp_gstr2) g_string_append_len(str, GSTR_LEN(tmp_gstr2)); else g_string_append_c(str, '-'); break; case AL_FORMAT_PATH: g_string_append_len(str, GSTR_LEN(req->uri.path)); break; case AL_FORMAT_SERVER_NAME: if (CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_NAME).string) g_string_append_len(str, GSTR_LEN(CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_NAME).string)); else g_string_append_len(str, GSTR_LEN(req->uri.host)); break; case AL_FORMAT_HOSTNAME: if (req->uri.host->len) g_string_append_len(str, GSTR_LEN(req->uri.host)); else g_string_append_c(str, '-'); break; case AL_FORMAT_CONNECTION_STATUS: { /* was request completed? */ liConnection *con = li_connection_from_vrequest(vr); /* try to get a connection object */ if (con && (con->in->is_closed && con->raw_out->is_closed && 0 == con->raw_out->length)) { g_string_append_c(str, 'X'); } else { g_string_append_c(str, vr->coninfo->keep_alive ? '+' : '-'); } } break; case AL_FORMAT_BYTES_IN: li_string_append_int(str, vr->coninfo->stats.bytes_in); break; case AL_FORMAT_BYTES_OUT: li_string_append_int(str, vr->coninfo->stats.bytes_out); break; default: /* not implemented: { 'C', FALSE, AL_FORMAT_COOKIE } { 't', FALSE, AL_FORMAT_TIME }, (partially implemented) */ g_string_append_c(str, '?'); break; } } else { /* append normal string */ g_string_append_len(str, GSTR_LEN(e->key)); } } return str; }
static void fastcgi_env_create(liVRequest *vr, liEnvironmentDup *envdup, GByteArray* buf) { liConInfo *coninfo = vr->coninfo; GString *tmp = vr->wrk->tmp_str; fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_SOFTWARE"), GSTR_LEN(CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_NAME"), GSTR_LEN(vr->request.uri.host)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("GATEWAY_INTERFACE"), CONST_STR_LEN("CGI/1.1")); { guint port = 0; switch (coninfo->local_addr.addr->plain.sa_family) { case AF_INET: port = coninfo->local_addr.addr->ipv4.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: port = coninfo->local_addr.addr->ipv6.sin6_port; break; #endif } if (port) { g_string_printf(tmp, "%u", htons(port)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_PORT"), GSTR_LEN(tmp)); } } fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_ADDR"), GSTR_LEN(coninfo->local_addr_str)); { guint port = 0; switch (coninfo->remote_addr.addr->plain.sa_family) { case AF_INET: port = coninfo->remote_addr.addr->ipv4.sin_port; break; #ifdef HAVE_IPV6 case AF_INET6: port = coninfo->remote_addr.addr->ipv6.sin6_port; break; #endif } if (port) { g_string_printf(tmp, "%u", htons(port)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("REMOTE_PORT"), GSTR_LEN(tmp)); } } fastcgi_env_add(buf, envdup, CONST_STR_LEN("REMOTE_ADDR"), GSTR_LEN(coninfo->remote_addr_str)); if (vr->request.content_length > 0) { g_string_printf(tmp, "%" L_GOFFSET_MODIFIER "i", vr->request.content_length); fastcgi_env_add(buf, envdup, CONST_STR_LEN("CONTENT_LENGTH"), GSTR_LEN(tmp)); } fastcgi_env_add(buf, envdup, CONST_STR_LEN("SCRIPT_NAME"), GSTR_LEN(vr->request.uri.path)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("PATH_INFO"), GSTR_LEN(vr->physical.pathinfo)); if (vr->physical.pathinfo->len) { g_string_truncate(tmp, 0); g_string_append_len(tmp, GSTR_LEN(vr->physical.doc_root)); /* TODO: perhaps an option for alternative doc-root? */ g_string_append_len(tmp, GSTR_LEN(vr->physical.pathinfo)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("PATH_TRANSLATED"), GSTR_LEN(tmp)); } fastcgi_env_add(buf, envdup, CONST_STR_LEN("SCRIPT_FILENAME"), GSTR_LEN(vr->physical.path)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("DOCUMENT_ROOT"), GSTR_LEN(vr->physical.doc_root)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("REQUEST_URI"), GSTR_LEN(vr->request.uri.raw_orig_path)); if (!g_string_equal(vr->request.uri.raw_orig_path, vr->request.uri.raw_path)) { fastcgi_env_add(buf, envdup, CONST_STR_LEN("REDIRECT_URI"), GSTR_LEN(vr->request.uri.raw_path)); } fastcgi_env_add(buf, envdup, CONST_STR_LEN("QUERY_STRING"), GSTR_LEN(vr->request.uri.query)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("REQUEST_METHOD"), GSTR_LEN(vr->request.http_method_str)); fastcgi_env_add(buf, envdup, CONST_STR_LEN("REDIRECT_STATUS"), CONST_STR_LEN("200")); /* if php is compiled with --force-redirect */ switch (vr->request.http_version) { case LI_HTTP_VERSION_1_1: fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_PROTOCOL"), CONST_STR_LEN("HTTP/1.1")); break; case LI_HTTP_VERSION_1_0: default: fastcgi_env_add(buf, envdup, CONST_STR_LEN("SERVER_PROTOCOL"), CONST_STR_LEN("HTTP/1.0")); break; } if (coninfo->is_ssl) { fastcgi_env_add(buf, envdup, CONST_STR_LEN("HTTPS"), CONST_STR_LEN("on")); } }
gboolean li_response_send_headers(liConnection *con) { GString *head; liVRequest *vr = con->mainvr; if (vr->response.http_status < 100 || vr->response.http_status > 999) { VR_ERROR(vr, "wrong status: %i", vr->response.http_status); return FALSE; } head = g_string_sized_new(8*1024-1); if (0 == con->out->length && con->mainvr->backend == NULL && vr->response.http_status >= 400 && vr->response.http_status < 600) { li_response_send_error_page(con); } if ((vr->response.http_status >= 100 && vr->response.http_status < 200) || vr->response.http_status == 204 || vr->response.http_status == 205 || vr->response.http_status == 304) { /* They never have a content-body/length */ li_chunkqueue_reset(con->out); con->out->is_closed = TRUE; con->raw_out->is_closed = TRUE; } else if (con->out->is_closed) { if (vr->request.http_method != LI_HTTP_METHOD_HEAD || con->out->length > 0) { /* do not send content-length: 0 if backend already skipped content generation for HEAD */ g_string_printf(con->wrk->tmp_str, "%"L_GOFFSET_FORMAT, con->out->length); li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Content-Length"), GSTR_LEN(con->wrk->tmp_str)); } } else if (con->info.keep_alive && vr->request.http_version == LI_HTTP_VERSION_1_1) { /* TODO: maybe someone set a content length header? */ if (!(vr->response.transfer_encoding & LI_HTTP_TRANSFER_ENCODING_CHUNKED)) { vr->response.transfer_encoding |= LI_HTTP_TRANSFER_ENCODING_CHUNKED; li_http_header_append(vr->response.headers, CONST_STR_LEN("Transfer-Encoding"), CONST_STR_LEN("chunked")); } } else { /* Unknown content length, no chunked encoding */ con->info.keep_alive = FALSE; } if (vr->request.http_method == LI_HTTP_METHOD_HEAD) { /* content-length is set, but no body */ li_chunkqueue_reset(con->out); con->out->is_closed = TRUE; con->raw_out->is_closed = TRUE; } /* Status line */ if (vr->request.http_version == LI_HTTP_VERSION_1_1) { g_string_append_len(head, CONST_STR_LEN("HTTP/1.1 ")); if (!con->info.keep_alive) li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); } else { g_string_append_len(head, CONST_STR_LEN("HTTP/1.0 ")); if (con->info.keep_alive) li_http_header_overwrite(vr->response.headers, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); } { guint len; gchar status_str[4]; gchar *str = li_http_status_string(vr->response.http_status, &len); li_http_status_to_str(vr->response.http_status, status_str); status_str[3] = ' '; g_string_append_len(head, status_str, 4); g_string_append_len(head, str, len); g_string_append_len(head, CONST_STR_LEN("\r\n")); } /* Append headers */ { liHttpHeader *header; GList *iter; gboolean have_date = FALSE, have_server = FALSE; for (iter = g_queue_peek_head_link(&vr->response.headers->entries); iter; iter = g_list_next(iter)) { header = (liHttpHeader*) iter->data; g_string_append_len(head, GSTR_LEN(header->data)); g_string_append_len(head, CONST_STR_LEN("\r\n")); if (!have_date && li_http_header_key_is(header, CONST_STR_LEN("date"))) have_date = TRUE; if (!have_server && li_http_header_key_is(header, CONST_STR_LEN("server"))) have_server = TRUE; } if (!have_date) { GString *d = li_worker_current_timestamp(con->wrk, LI_GMTIME, LI_TS_FORMAT_HEADER); /* HTTP/1.1 requires a Date: header */ g_string_append_len(head, CONST_STR_LEN("Date: ")); g_string_append_len(head, GSTR_LEN(d)); g_string_append_len(head, CONST_STR_LEN("\r\n")); } if (!have_server) { GString *tag = CORE_OPTIONPTR(LI_CORE_OPTION_SERVER_TAG).string; if (tag->len) { g_string_append_len(head, CONST_STR_LEN("Server: ")); g_string_append_len(head, GSTR_LEN(tag)); g_string_append_len(head, CONST_STR_LEN("\r\n")); } } } g_string_append_len(head, CONST_STR_LEN("\r\n")); li_chunkqueue_append_string(con->raw_out, head); return TRUE; }
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")); }