Notes from Apache HTTPD Source Code
A nameless tech company leads the world in the anti-piracy / anti-personal-privacy movement while being the 6th most cash rich in the USA. And they've given me.. $499 Upgrades of the same product 15 years in a row? I bought a laptop yesterday so my brush with piracy is still very fresh.
Don't let the economic vultures steal your dreams. Contribute to the open-source software movement.
A shortcut past difficult coding questions is by looking for someone else who's already done it. The best. So when I am dealing with technical questions that just don't have published answers.. I want to look at the code and see for myself what is going on. I almost always have one editor or another running to paste bits of code or comments I find in, to look at in more detail later. I'm all about finding solutions as fast as I can, I'm used to obstacles on the net.
For many years I learned about networking technology from the outside in. Instead of say learning about Apache by administrating servers like I do today, I learned about them in reverse. I wasn't building servers or programming daemons, I was learning about the flaws they had and what made them work.
Open source is the best learning tool on the planet, and some of the best can be found in all the various work done by Apache... Especially the Server project, which has a lonnnnnnng history of the best programmers and researchers on the planet helping to build a free product that single-handedly sparked a revolution that has powered our world the last 15 years. Free. Open Source. Copied by others. This organization is responsible in large part for the evolution of the Internet and our interaction with it daily.. Apache servers are exhanging bitts and transmitting bytes at this very second.
So I found these notes
15min ago I was asking the Apache source code for some answers for the this password plugin, and thought I'd take a break from coding and post about how open-source is such a great tool for finding the best answers to the toughest questions, for me and this site only apache can answer many of the questions and answers dealth with here.
In fact, that's exactly the reason I'm so fond of saying, Ask Apache. Just check out these Notes!
request_rec ap_regmatch_t regmatch[AP_MAX_REG_MATCH]; apr_array_header_t *rewriteconds; rewritecond_entry *conds; int i, rc; char *newuri = NULL; request_rec *r = ctx->r; int is_proxyreq = 0; /* Information to which an extension can be mapped */ typedef struct extension_info { char *forced_type; /* Additional AddTyped stuff */ char *encoding_type; /* Added with AddEncoding... */ char *language_type; /* Added with AddLanguage... */ char *handler; /* Added with AddHandler... */ char *charset_type; /* Added with AddCharset... */ char *input_filters; /* Added with AddInputFilter... */ char *output_filters; /* Added with AddOutputFilter... */ static const command_rec mime_cmds[] = { AP_INIT_ITERATE2("AddCharset", add_extension_info, (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO, "a charset (e.g., iso-2022-jp), followed by one or more " "file extensions"), AP_INIT_ITERATE2("AddEncoding", add_extension_info, (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO, "an encoding (e.g., gzip), followed by one or more file extensions"), AP_INIT_ITERATE2("AddHandler", add_extension_info, (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO, "a handler name followed by one or more file extensions"), AP_INIT_ITERATE2("AddInputFilter", add_extension_info, (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO, "input filter name (or ; delimited names) followed by one or " "more file extensions"), AP_INIT_ITERATE2("AddLanguage", add_extension_info, (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO, "a language (e.g., fr), followed by one or more file extensions"), AP_INIT_ITERATE2("AddOutputFilter", add_extension_info, (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO, "output filter name (or ; delimited names) followed by one or " "more file extensions"), AP_INIT_ITERATE2("AddType", add_extension_info, (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO, "a mime type followed by one or more file extensions"), AP_INIT_TAKE1("DefaultLanguage", ap_set_string_slot, (void*)APR_OFFSETOF(mime_dir_config, default_language), OR_FILEINFO, "language to use for documents with no other language file extension"), AP_INIT_ITERATE("MultiviewsMatch", multiviews_match, NULL, OR_FILEINFO, "NegotiatedOnly (default), Handlers and/or Filters, or Any"), AP_INIT_ITERATE("RemoveCharset", remove_extension_info, (void *)APR_OFFSETOF(extension_info, charset_type), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveEncoding", remove_extension_info, (void *)APR_OFFSETOF(extension_info, encoding_type), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveHandler", remove_extension_info, (void *)APR_OFFSETOF(extension_info, handler), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveInputFilter", remove_extension_info, (void *)APR_OFFSETOF(extension_info, input_filters), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveLanguage", remove_extension_info, (void *)APR_OFFSETOF(extension_info, language_type), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveOutputFilter", remove_extension_info, (void *)APR_OFFSETOF(extension_info, output_filters), OR_FILEINFO, "one or more file extensions"), AP_INIT_ITERATE("RemoveType", remove_extension_info, (void *)APR_OFFSETOF(extension_info, forced_type), OR_FILEINFO, "one or more file extensions"), AP_INIT_TAKE1("TypesConfig", set_types_config, NULL, RSRC_CONF, "the MIME types config file"), AP_INIT_FLAG("ModMimeUsePathInfo", ap_set_flag_slot, (void *)APR_OFFSETOF(mime_dir_config, use_path_info), ACCESS_CONF, "Set to 'yes' to allow mod_mime to use path info for type checking"), {NULL} }; /** * 'allowed' is a bitvector of the allowed methods. * * A handler must ensure that the request method is one that * it is capable of handling. Generally modules should DECLINE * any request methods they do not handle. Prior to aborting the * handler like this the handler should set r->allowed to the list * of methods that it is willing to handle. This bitvector is used * to construct the "Allow:" header required for OPTIONS requests, * and HTTP_METHOD_NOT_ALLOWED and HTTP_NOT_IMPLEMENTED status codes. * * Since the default_handler deals with OPTIONS, all modules can * usually decline to deal with OPTIONS. TRACE is always allowed, * modules don't need to set it explicitly. * * Since the default_handler will always handle a GET, a * module which does *not* implement GET should probably return * HTTP_METHOD_NOT_ALLOWED. Unfortunately this means that a Script GET * handler can't be installed by mod_actions. */ /** * @defgroup Methods List of Methods recognized by the server * @ingroup APACHE_CORE_DAEMON * @{ * * @brief Methods recognized (but not necessarily handled) by the server. * * These constants are used in bit shifting masks of size int, so it is * unsafe to have more methods than bits in an int. HEAD == M_GET. * This list must be tracked by the list in http_protocol.c in routine * ap_method_name_of(). * */ #define M_GET 0 /** RFC 2616: HTTP */ #define M_PUT 1 /* : */ #define M_POST 2 #define M_DELETE 3 #define M_CONNECT 4 #define M_OPTIONS 5 #define M_TRACE 6 /** RFC 2616: HTTP */ #define M_PATCH 7 /** no rfc(!) ### remove this one? */ #define M_PROPFIND 8 /** RFC 2518: WebDAV */ #define M_PROPPATCH 9 /* : */ #define M_MKCOL 10 #define M_COPY 11 #define M_MOVE 12 #define M_LOCK 13 #define M_UNLOCK 14 /** RFC 2518: WebDAV */ #define M_VERSION_CONTROL 15 /** RFC 3253: WebDAV Versioning */ #define M_CHECKOUT 16 /* : */ #define M_UNCHECKOUT 17 #define M_CHECKIN 18 #define M_UPDATE 19 #define M_LABEL 20 #define M_REPORT 21 #define M_MKWORKSPACE 22 #define M_MKACTIVITY 23 #define M_BASELINE_CONTROL 24 #define M_MERGE 25 #define M_INVALID 26 /** RFC 3253: WebDAV Versioning */ { methods_registry = apr_hash_make(p); apr_pool_cleanup_register(p, NULL, ap_method_registry_destroy, apr_pool_cleanup_null); /* put all the standard methods into the registry hash to ease the mapping operations between name and number */ register_one_method(p, "GET", M_GET); register_one_method(p, "PUT", M_PUT); register_one_method(p, "POST", M_POST); register_one_method(p, "DELETE", M_DELETE); register_one_method(p, "CONNECT", M_CONNECT); register_one_method(p, "OPTIONS", M_OPTIONS); register_one_method(p, "TRACE", M_TRACE); register_one_method(p, "PATCH", M_PATCH); register_one_method(p, "PROPFIND", M_PROPFIND); register_one_method(p, "PROPPATCH", M_PROPPATCH); register_one_method(p, "MKCOL", M_MKCOL); register_one_method(p, "COPY", M_COPY); register_one_method(p, "MOVE", M_MOVE); register_one_method(p, "LOCK", M_LOCK); register_one_method(p, "UNLOCK", M_UNLOCK); register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL); register_one_method(p, "CHECKOUT", M_CHECKOUT); register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT); register_one_method(p, "CHECKIN", M_CHECKIN); register_one_method(p, "UPDATE", M_UPDATE); register_one_method(p, "LABEL", M_LABEL); register_one_method(p, "REPORT", M_REPORT); register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE); register_one_method(p, "MKACTIVITY", M_MKACTIVITY); register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL); register_one_method(p, "MERGE", M_MERGE); /** * @defgroup HTTP_Status HTTP Status Codes * @{ */ /** * The size of the static array in http_protocol.c for storing * all of the potential response status-lines (a sparse table). * A future version should dynamically generate the apr_table_t at startup. */ #define RESPONSE_CODES 57 #define HTTP_CONTINUE 100 #define HTTP_SWITCHING_PROTOCOLS 101 #define HTTP_PROCESSING 102 #define HTTP_OK 200 #define HTTP_CREATED 201 #define HTTP_ACCEPTED 202 #define HTTP_NON_AUTHORITATIVE 203 #define HTTP_NO_CONTENT 204 #define HTTP_RESET_CONTENT 205 #define HTTP_PARTIAL_CONTENT 206 #define HTTP_MULTI_STATUS 207 #define HTTP_MULTIPLE_CHOICES 300 #define HTTP_MOVED_PERMANENTLY 301 #define HTTP_MOVED_TEMPORARILY 302 #define HTTP_SEE_OTHER 303 #define HTTP_NOT_MODIFIED 304 #define HTTP_USE_PROXY 305 #define HTTP_TEMPORARY_REDIRECT 307 #define HTTP_BAD_REQUEST 400 #define HTTP_UNAUTHORIZED 401 #define HTTP_PAYMENT_REQUIRED 402 #define HTTP_FORBIDDEN 403 #define HTTP_NOT_FOUND 404 #define HTTP_METHOD_NOT_ALLOWED 405 #define HTTP_NOT_ACCEPTABLE 406 #define HTTP_PROXY_AUTHENTICATION_REQUIRED 407 #define HTTP_REQUEST_TIME_OUT 408 #define HTTP_CONFLICT 409 #define HTTP_GONE 410 #define HTTP_LENGTH_REQUIRED 411 #define HTTP_PRECONDITION_FAILED 412 #define HTTP_REQUEST_ENTITY_TOO_LARGE 413 #define HTTP_REQUEST_URI_TOO_LARGE 414 #define HTTP_UNSUPPORTED_MEDIA_TYPE 415 #define HTTP_RANGE_NOT_SATISFIABLE 416 #define HTTP_EXPECTATION_FAILED 417 #define HTTP_UNPROCESSABLE_ENTITY 422 #define HTTP_LOCKED 423 #define HTTP_FAILED_DEPENDENCY 424 #define HTTP_UPGRADE_REQUIRED 426 #define HTTP_INTERNAL_SERVER_ERROR 500 #define HTTP_NOT_IMPLEMENTED 501 #define HTTP_BAD_GATEWAY 502 #define HTTP_SERVICE_UNAVAILABLE 503 #define HTTP_GATEWAY_TIME_OUT 504 #define HTTP_VERSION_NOT_SUPPORTED 505 #define HTTP_VARIANT_ALSO_VARIES 506 #define HTTP_INSUFFICIENT_STORAGE 507 #define HTTP_NOT_EXTENDED 510 /* The max method number. Method numbers are used to shift bitmasks, * so this cannot exceed 63, and all bits high is equal to -1, which is a * special flag, so the last bit used has index 62. */ #define METHOD_NUMBER_LAST 62 static const char * status_lines[RESPONSE_CODES] = #else static const char * const status_lines[RESPONSE_CODES] = #endif { "100 Continue", "101 Switching Protocols", "102 Processing", #define LEVEL_200 3 "200 OK", "201 Created", "202 Accepted", "203 Non-Authoritative Information", "204 No Content", "205 Reset Content", "206 Partial Content", "207 Multi-Status", #define LEVEL_300 11 "300 Multiple Choices", "301 Moved Permanently", "302 Found", "303 See Other", "304 Not Modified", "305 Use Proxy", "306 unused", "307 Temporary Redirect", #define LEVEL_400 19 "400 Bad Request", "401 Authorization Required", "402 Payment Required", "403 Forbidden", "404 Not Found", "405 Method Not Allowed", "406 Not Acceptable", "407 Proxy Authentication Required", "408 Request Time-out", "409 Conflict", "410 Gone", "411 Length Required", "412 Precondition Failed", "413 Request Entity Too Large", "414 Request-URI Too Large", "415 Unsupported Media Type", "416 Requested Range Not Satisfiable", "417 Expectation Failed", "418 unused", "419 unused", "420 unused", "421 unused", "422 Unprocessable Entity", "423 Locked", "424 Failed Dependency", /* This is a hack, but it is required for ap_index_of_response * to work with 426. */ "425 No code", "426 Upgrade Required", #define LEVEL_500 46 "500 Internal Server Error", "501 Method Not Implemented", "502 Bad Gateway", "503 Service Temporarily Unavailable", "504 Gateway Time-out", "505 HTTP Version Not Supported", "506 Variant Also Negotiates", "507 Insufficient Storage", "508 unused", "509 unused", "510 Not Extended" }; /** is the status code informational */ #define ap_is_HTTP_INFO(x) (((x) >= 100)&&((x) < 200)) /** is the status code OK ?*/ #define ap_is_HTTP_SUCCESS(x) (((x) >= 200)&&((x) < 300)) /** is the status code a redirect */ #define ap_is_HTTP_REDIRECT(x) (((x) >= 300)&&((x) < 400)) /** is the status code a error (client or server) */ #define ap_is_HTTP_ERROR(x) (((x) >= 400)&&((x) < 600)) /** is the status code a client error */ #define ap_is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500)) /** is the status code a server error */ #define ap_is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600)) /** is the status code a (potentially) valid response code? */ #define ap_is_HTTP_VALID_RESPONSE(x) (((x) >= 100)&&((x) < 600)) /** should the status code drop the connection */ #define ap_status_drops_connection(x) (((x) == HTTP_BAD_REQUEST) || ((x) == HTTP_REQUEST_TIME_OUT) || ((x) == HTTP_LENGTH_REQUIRED) || ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || ((x) == HTTP_REQUEST_URI_TOO_LARGE) || ((x) == HTTP_INTERNAL_SERVER_ERROR) || ((x) == HTTP_SERVICE_UNAVAILABLE) || ((x) == HTTP_NOT_IMPLEMENTED)) /* * mod_headers.c: Add/append/remove HTTP response headers * Written by Paul Sutton, paul@ukweb.com, 1 Oct 1996 * * The Header directive can be used to add/replace/remove HTTP headers * within the response message. The RequestHeader directive can be used * to add/replace/remove HTTP headers before a request message is processed. * Valid in both per-server and per-dir configurations. * * Syntax is: * * Header action header value * RequestHeader action header value * * Where action is one of: * set - set this header, replacing any old value * add - add this header, possible resulting in two or more * headers with the same name * append - append this text onto any existing header of this same * unset - remove this header * * Where action is unset, the third argument (value) should not be given. * The header name can include the colon, or not. * * The Header and RequestHeader directives can only be used where allowed * by the FileInfo override. * * When the request is processed, the header directives are processed in * this order: firstly, the main server, then the virtual server handling * this request (if any), then any <directory> sections (working downwards * from the root dir), then an <location> sections (working down from * shortest URL component), the any <file> sections. This order is * important if any 'set' or 'unset' actions are used. For example, * the following two directives have different effect if applied in * the reverse order: * * Header append Author "John P. Doe" * Header unset Author * * Examples: * * To set the "Author" header, use * Header add Author "John P. Doe" * * To remove a header: * Header unset Author * */ register_format_tag_handler("D", (const void *)header_request_duration); register_format_tag_handler("t", (const void *)header_request_time); register_format_tag_handler("e", (const void *)header_request_env_var); register_format_tag_handler("s", (const void *)header_request_ssl_var); typedef enum { hdr_add = 'a', /* add header (could mean multiple hdrs) */ hdr_set = 's', /* set (replace old value) */ hdr_append = 'm', /* append (merge into any old value) */ hdr_unset = 'u', /* unset header */ hdr_echo = 'e', /* echo headers from request to response */ hdr_edit = 'r' /* change value by regexp */ } hdr_actions; /* * magic cmd->info values */ static char hdr_in = '0'; /* RequestHeader */ static char hdr_out = '1'; /* Header onsuccess */ static char hdr_err = '2'; /* Header always */ /* * A format string consists of white space, text and optional format * tags in any order. E.g., * * Header add MyHeader "Free form text %D %t more text" * * Decompose the format string into its tags. Each tag (struct format_tag) * contains a pointer to the function used to format the tag. Then save each * tag in the tag array anchored in the header_entry. */ return "first argument must be 'add', 'set', 'append', 'unset', " "'echo' or 'edit'."; if (new->action == hdr_edit) { if (subs == NULL) { return "Header edit requires a match and a substitution"; } if (new->action == hdr_edit) { if (subs == NULL) { return "Header edit requires a match and a substitution"; } new->regex = ap_pregcomp(cmd->pool, value, AP_REG_EXTENDED); if (new->regex == NULL) { return "Header edit regex could not be compiled"; } new->subs = subs; } else { /* there's no subs, so envclause is really that argument */ if (envclause != NULL) { return "Too many arguments to directive"; } envclause = subs; } if (new->action == hdr_unset) { if (value) { if (envclause) { return "header unset takes two arguments"; } envclause = value; value = NULL; } } else if (new->action == hdr_echo) { ap_regex_t *regex; if (value) { if (envclause) { return "Header echo takes two arguments"; } envclause = value; value = NULL; } if (cmd->info != &hdr_out && cmd->info != &hdr_err) return "Header echo only valid on Header " "directives"; else { regex = ap_pregcomp(cmd->pool, hdr, AP_REG_EXTENDED | AP_REG_NOSUB); if (regex == NULL) { return "Header echo regex could not be compiled"; } } new->regex = regex; } else if (!value) return "Header requires three arguments"; /* Handle the envclause on Header */ if (envclause != NULL) { if (strcasecmp(envclause, "early") == 0) { condition_var = condition_early; } else { if (strncasecmp(envclause, "env=", 4) != 0) { return "error: envclause should be in the form env=envar"; } if ((envclause[4] == '