📄 protocol.cpp
字号:
/* * Copyright (c) 1999-2008 Caucho Technology. All rights reserved. * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson *//* * SSL client certificate contributed by Ahn Le *//* * Anh: We have to define _WIN32_WINNT as 0x0400 to have access to * the Crypto API. By definning as this way, the dll can only work * with Windows 95 OEM Service Release 2 or above. */ #define _WIN32_WINNT 0x0400#include <stdlib.h>#include <stdio.h>#include <stdarg.h>#include <windows.h>#include "httpext.h"#include <errno.h>#include <ctype.h>#include <string.h>#define ISAPI_SCRIPT "/scripts/isapi_srun.dll"extern "C" {#include "../common/cse.h"#include "../common/version.h"}extern "C" {voidcse_error(config_t *config, char *fmt, ...){ va_list arg; char buf[1024]; va_start(arg, fmt); if (fmt) vsprintf(buf, fmt, arg); else buf[0] = 0; va_end(arg); if (buf[0]) { config->error = strdup(buf); config->enable_caucho_status = 1; }#ifdef DEBUG { FILE *file; file = fopen("/temp/isapi.log", "a+b"); fprintf(file, "%s\n", buf); fclose(file); }#endif}void *cse_malloc(int size){ return malloc(size);}void cse_free(config_t *config, void *value) {}voidcse_set_socket_cleanup(int socket, void *pool){}voidcse_kill_socket_cleanup(int socket, void *pool){}}voidcse_log(char *fmt, ...){#ifdef DEBUG va_list arg; FILE *file; file = fopen("/temp/isapi.log", "a+"); va_start(arg, fmt); if (file) vfprintf(file, fmt, arg); va_end(arg); fclose(file);#endif}void *cse_create_lock(config_t *config){ return CreateMutex(0, false, 0);}voidcse_free_lock(config_t *config, void *lock){}intcse_lock(void *lock){ if (lock) { WaitForSingleObject(lock, INFINITE); } return 1;}voidcse_unlock(void *lock){ if (lock) { ReleaseMutex(lock); }}static voidcse_printf(EXTENSION_CONTROL_BLOCK *r, char *fmt, ...){ va_list args; char buf[4096]; unsigned long len; va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); len = strlen(buf); r->WriteClient(r->ConnID, buf, &len, 0);}static voidcse_pad(EXTENSION_CONTROL_BLOCK *r){ cse_printf(r, "\n\n\n\n"); cse_printf(r, "<!--\n"); cse_printf(r, " - Unfortunately, Microsoft has added a clever new\n"); cse_printf(r, " - \"feature\" to Internet Explorer. If the text in\n"); cse_printf(r, " - an error's message is \"too small\", specifically\n"); cse_printf(r, " - less than 512 bytes, Internet Explorer returns\n"); cse_printf(r, " - its own error message. Yes, you can turn that\n"); cse_printf(r, " - off, but *surprise* it's pretty tricky to find\n"); cse_printf(r, " - buried as a switch called \"smart error\n"); cse_printf(r, " - messages\" That means, of course, that many of\n"); cse_printf(r, " - Resin's error messages are censored by default.\n"); cse_printf(r, " - And, of course, you'll be shocked to learn that\n"); cse_printf(r, " - IIS always returns error messages that are long\n"); cse_printf(r, " - enough to make Internet Explorer happy. The\n"); cse_printf(r, " - workaround is pretty simple: pad the error\n"); cse_printf(r, " - message with a big comment to push it over the\n"); cse_printf(r, " - five hundred and twelve byte minimum. Of course,\n"); cse_printf(r, " - that's exactly what you're reading right now.\n"); cse_printf(r, " -->\n");}static intconnection_error(config_t *config, EXTENSION_CONTROL_BLOCK *r){ // r->content_type = "text/html"; // ap_send_http_header(r); char *hostname = 0; int port = 0; if (config->error_page && config->error_page[0]) { DWORD size = strlen(config->error_page); DWORD type = 0; cse_printf(r, "HTTP/1.0 302 Redirect\r\n"); cse_printf(r, "Location: %s\r\n", config->error_page); cse_printf(r, "\r\n"); return 1; } cse_printf(r, "HTTP/1.0 503 Busy\n\n"); cse_printf(r, "<html><body bgcolor='white'>\n"); cse_printf(r, "<h1>Server is currently unavailable or down for maintenance\n"); cse_printf(r, "</h1>\n"); cse_printf(r, "</body></html>\n"); cse_pad(r); return 1;}static intcse_error(config_t *config, EXTENSION_CONTROL_BLOCK *r){ // r->content_type = "text/html"; // ap_send_http_header(r); if (config->error_page) { DWORD size = strlen(config->error_page); DWORD type = 0; cse_printf(r, "HTTP/1.0 302 Redirect\n"); cse_printf(r, "Location: %s\n", config->error_page); cse_printf(r, "\n"); return 1; } cse_printf(r, "HTTP/1.0 500 Server Error\n\n"); cse_printf(r, "<html><body bgcolor='white'>\n"); cse_printf(r, "<h1>Can't access URL</h1>\n"); if (config->error) cse_printf(r, "<pre>%s</pre>", config->error); cse_printf(r, "</body></html>\n"); cse_pad(r); return 1;}static voidwrite_var(stream_t *s, EXTENSION_CONTROL_BLOCK *r, char *name, int code){ char buf[BUF_LENGTH]; char *ptr; unsigned long size = sizeof(buf); buf[0] = 0; if (r->GetServerVariable(r->ConnID, name, buf, &size) && size > 0 && buf[0]) { buf[size] = 0; for (ptr = buf; isspace(*ptr); ptr++) { } cse_write_string(s, code, ptr); }}static voidwrite_header(stream_t *s, EXTENSION_CONTROL_BLOCK *r, char *name){ char buf[BUF_LENGTH]; unsigned long size = sizeof(buf); char *ptr = buf; buf[0] = 0; if (r->GetServerVariable(r->ConnID, name, buf, &size) && size > 0 && buf[0]) { for (; size > 0 && isspace(buf[size - 1]); size--) { } buf[size] = 0; cse_write_string(s, HMUX_HEADER, name); for (ptr = buf; isspace(*ptr); ptr++) { } cse_write_string(s, HMUX_STRING, ptr); }}/** * Writes SSL data, including client certificates. */static voidwrite_ssl(stream_t *s, EXTENSION_CONTROL_BLOCK *r){ char buf[BUF_LENGTH]; unsigned long size = sizeof(buf); if (! r->GetServerVariable(r->ConnID, "SERVER_PORT_SECURE", buf, &size) || size <= 0 || buf[0] != '1') return; cse_write_string(s, CSE_IS_SECURE, ""); // Anh : Add SSL connection informations cse_write_string(s, HMUX_HEADER, "HTTPS"); cse_write_string(s, HMUX_STRING, "on"); write_header(s, r, "HTTPS_KEYSIZE"); write_header(s, r, "HTTPS_SECRETKEYSIZE"); // Anh : Check client certificate existence size = sizeof(buf); buf[0] = 0; if (! r->GetServerVariable(r->ConnID, "CERT_FLAGS", buf, &size) || size <= 0 || buf[0] != '1') return; // There is a client certificate char cert_buf[BUF_LENGTH]={0}; CERT_CONTEXT_EX cert; cert.cbAllocated = sizeof(cert_buf); cert.CertContext.pbCertEncoded = (BYTE*) cert_buf; cert.CertContext.cbCertEncoded = 0; DWORD dwSize = sizeof(cert); if (r->ServerSupportFunction(r->ConnID, (DWORD)HSE_REQ_GET_CERT_INFO_EX, (LPVOID)&cert, &dwSize,NULL) != FALSE) { // cert now contains valid client certificate information LOG(("\ndwCertEncodingType = %d (%d) %ld\n", cert.CertContext.dwCertEncodingType & X509_ASN_ENCODING , cert.CertContext.cbCertEncoded, cert.dwCertificateFlags)); cse_write_packet(s, CSE_CLIENT_CERT, (char *)cert.CertContext.pbCertEncoded, cert.CertContext.cbCertEncoded); write_header(s, r, "CERT_ISSUER"); write_header(s, r, "CERT_SERIALNUMBER"); write_header(s, r, "CERT_SUBJECT"); write_header(s, r, "CERT_SERVER_ISSUER"); write_header(s, r, "CERT_SERVER_SUBJECT"); }}static inthexify(char *uri, int offset, int ch){ int d1 = (ch >> 4) & 0xf; int d2 = ch & 0xf; uri[offset++] = '%'; uri[offset++] = (d1 < 10) ? (d1 + '0') : (d1 - 10 + 'A'); uri[offset++] = (d2 < 10) ? (d2 + '0') : (d2 - 10 + 'A'); return offset;}static int write_env(stream_t *s, EXTENSION_CONTROL_BLOCK *r){ int isHttp11 = 0; char protocol[BUF_LENGTH]; char path_info_buffer[BUF_LENGTH]; char *path_info = path_info_buffer; char uri_buffer[BUF_LENGTH]; char *uri = uri_buffer; unsigned long size = sizeof(protocol); if (r->GetServerVariable(r->ConnID, "SERVER_PROTOCOL", protocol, &size) && size > 0) { protocol[size] = 0; isHttp11 = ! strcmp(protocol, "HTTP/1.1"); } size = sizeof(path_info_buffer); if (r->GetServerVariable(r->ConnID, "PATH_INFO", path_info, &size) && size > 0) { int i; path_info[size] = 0; if (! strncmp(path_info, ISAPI_SCRIPT, sizeof(ISAPI_SCRIPT) - 1)) path_info += sizeof(ISAPI_SCRIPT) - 1; i = 0; while (i < BUF_LENGTH - 6) { int ch = *path_info++ & 0xff; if (ch == 0) break; else if (' ' <= ch && ch < 0x80 && ch != '%') { uri[i++] = ch; } else if (ch < 0x80) { i = hexify(uri, i, ch); } else { i = hexify(uri, i, 0xc0 | ((ch >> 6) & 0x1f)); i = hexify(uri, i, 0x80 | (ch & 0x3f)); } } uri[i] = 0; } else uri[size] = 0; hmux_start_channel(s, 1); cse_write_string(s, HMUX_URL, uri); write_var(s, r, "REQUEST_METHOD", HMUX_METHOD); write_var(s, r, "SERVER_PROTOCOL", CSE_PROTOCOL); // write_var(s, r, "PATH_TRANSLATED", CSE_PATH_TRANSLATED); write_var(s, r, "QUERY_STRING", CSE_QUERY_STRING); write_var(s, r, "SERVER_NAME", HMUX_SERVER_NAME); write_var(s, r, "SERVER_PORT", CSE_SERVER_PORT); write_var(s, r, "REMOTE_HOST", CSE_REMOTE_HOST); write_var(s, r, "REMOTE_ADDR", CSE_REMOTE_ADDR); write_var(s, r, "REMOTE_USER", CSE_REMOTE_USER); write_var(s, r, "AUTH_TYPE", CSE_AUTH_TYPE); // write_var(s, r, "CONTENT_TYPE", CSE_CONTENT_TYPE); // write_var(s, r, "CONTENT_LENGTH", CSE_CONTENT_LENGTH); // cse_write_string(s, CSE_DOCROOT, ap_document_root(r)); // sprintf(buf, "%d", s->srun->session); cse_write_string(s, CSE_SERVER_TYPE, "ISAPI"); write_ssl(s, r); return isHttp11;}static voidwrite_headers(stream_t *s, EXTENSION_CONTROL_BLOCK *r){ char buf[16384]; unsigned long i = 0; unsigned long len = sizeof(buf); if (! r->GetServerVariable(r->ConnID, "ALL_RAW", buf, &len)) return; while (i < len) { int ch; int j; for (; i < len && isspace(buf[i]); i++) { } int head = i; int tail; for (; i < len && (ch = buf[i]) != ':'; i++) { if (isspace(ch)) buf[i] = 0; } buf[i] = 0; for (i++; (i < len && ((ch = buf[i]) == ' ' || ch == '\t') && ch != '\n'); i++) { } tail = i; for (; i < len && (buf[i] != '\n' || isspace(buf[i+1])); i++) { if (isspace(buf[i])) buf[i] = ' '; } for (j = i - 1; tail <= j && isspace(buf[j]); j--) { buf[j] = 0; } buf[i++] = 0; if (buf[head]) { cse_write_string(s, HMUX_HEADER, buf + head); cse_write_string(s, HMUX_STRING, buf + tail); } }}static intwrite_client_buffer(EXTENSION_CONTROL_BLOCK *r, void *v_buf, int len){ char *buffer = (char *) v_buf; while (len > 0) { unsigned long sentlen = len; if (! r->WriteClient(r->ConnID, buffer, &sentlen, HSE_IO_SYNC) || sentlen <= 0) { return -1; } len -= sentlen; buffer += sentlen; } return 0;}static intcse_write_response(stream_t *s, unsigned long len, EXTENSION_CONTROL_BLOCK *r){ while (len > 0) { unsigned long sublen; if (s->read_offset >= s->read_length) { if (cse_fill_buffer(s) < 0) { connection_error(s->config, r); return -1; } } sublen = s->read_length - s->read_offset; if (len < sublen) sublen = len; s->read_buf[s->read_length] = 0; if (write_client_buffer(r, s->read_buf + s->read_offset,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -