|
| 1 | +/* |
| 2 | + * mod_example_2.c: Example module for Apache HTTP Server 2.4 |
| 3 | + * This module calculates and displays MD5 or SHA1 digests of files. |
| 4 | + */ |
| 5 | + |
| 6 | +#include "httpd.h" |
| 7 | +#include "http_config.h" |
| 8 | +#include "http_protocol.h" |
| 9 | +#include "ap_config.h" |
| 10 | +#include "apr_md5.h" |
| 11 | +#include "apr_sha1.h" |
| 12 | +#include "apr_file_io.h" |
| 13 | +#include "apr_tables.h" |
| 14 | + |
| 15 | +static int example_handler(request_rec *r) |
| 16 | +{ |
| 17 | + int rc, exists; |
| 18 | + apr_finfo_t finfo; |
| 19 | + apr_file_t *file; |
| 20 | + char *filename; |
| 21 | + char buffer[256]; |
| 22 | + apr_size_t readBytes; |
| 23 | + int n; |
| 24 | + apr_table_t *GET; |
| 25 | + apr_array_header_t *POST; |
| 26 | + const char *digestType; |
| 27 | + |
| 28 | + |
| 29 | + /* Check that the "example-handler" handler is being called. */ |
| 30 | + if (!r->handler || strcmp(r->handler, "example-handler")) return (DECLINED); |
| 31 | + |
| 32 | + /* Figure out which file is being requested by removing the .sum from it */ |
| 33 | + filename = apr_pstrdup(r->pool, r->filename); |
| 34 | + filename[strlen(filename)-4] = 0; /* Cut off the last 4 characters. */ |
| 35 | + |
| 36 | + /* Figure out if the file we request a sum on exists and isn't a directory */ |
| 37 | + rc = apr_stat(&finfo, filename, APR_FINFO_MIN, r->pool); |
| 38 | + if (rc == APR_SUCCESS) { |
| 39 | + exists = |
| 40 | + ( |
| 41 | + (finfo.filetype != APR_NOFILE) |
| 42 | + && !(finfo.filetype & APR_DIR) |
| 43 | + ); |
| 44 | + if (!exists) return HTTP_NOT_FOUND; /* Return a 404 if not found. */ |
| 45 | + } |
| 46 | + /* If apr_stat failed, we're probably not allowed to check this file. */ |
| 47 | + else return HTTP_FORBIDDEN; |
| 48 | + |
| 49 | + /* Parse the GET and, optionally, the POST data sent to us */ |
| 50 | + |
| 51 | + ap_args_to_table(r, &GET); |
| 52 | + ap_parse_form_data(r, NULL, &POST, -1, 8192); |
| 53 | + |
| 54 | + /* Set the appropriate content type */ |
| 55 | + ap_set_content_type(r, "text/html"); |
| 56 | + |
| 57 | + /* Print a title and some general information */ |
| 58 | + ap_rprintf(r, "<h2>Information on %s:</h2>", filename); |
| 59 | + ap_rprintf(r, "<b>Size:</b> %" APR_OFF_T_FMT " bytes<br/>", finfo.size); |
| 60 | + |
| 61 | + /* Get the digest type the client wants to see */ |
| 62 | + digestType = apr_table_get(GET, "digest"); |
| 63 | + if (!digestType) digestType = "MD5"; |
| 64 | + |
| 65 | + |
| 66 | + rc = apr_file_open(&file, filename, APR_READ, APR_OS_DEFAULT, r->pool); |
| 67 | + if (rc == APR_SUCCESS) { |
| 68 | + |
| 69 | + /* Are we trying to calculate the MD5 or the SHA1 digest? */ |
| 70 | + if (!strcasecmp(digestType, "md5")) { |
| 71 | + /* Calculate the MD5 sum of the file */ |
| 72 | + union { |
| 73 | + char chr[16]; |
| 74 | + uint32_t num[4]; |
| 75 | + } digest; |
| 76 | + apr_md5_ctx_t md5; |
| 77 | + apr_md5_init(&md5); |
| 78 | + readBytes = 256; |
| 79 | + while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { |
| 80 | + apr_md5_update(&md5, buffer, readBytes); |
| 81 | + } |
| 82 | + apr_md5_final(digest.chr, &md5); |
| 83 | + |
| 84 | + /* Print out the MD5 digest */ |
| 85 | + ap_rputs("<b>MD5: </b><code>", r); |
| 86 | + for (n = 0; n < APR_MD5_DIGESTSIZE/4; n++) { |
| 87 | + ap_rprintf(r, "%08x", digest.num[n]); |
| 88 | + } |
| 89 | + ap_rputs("</code>", r); |
| 90 | + /* Print a link to the SHA1 version */ |
| 91 | + ap_rputs("<br/><a href='?digest=sha1'>View the SHA1 hash instead</a>", r); |
| 92 | + } |
| 93 | + else { |
| 94 | + /* Calculate the SHA1 sum of the file */ |
| 95 | + union { |
| 96 | + char chr[20]; |
| 97 | + uint32_t num[5]; |
| 98 | + } digest; |
| 99 | + apr_sha1_ctx_t sha1; |
| 100 | + apr_sha1_init(&sha1); |
| 101 | + readBytes = 256; |
| 102 | + while ( apr_file_read(file, buffer, &readBytes) == APR_SUCCESS ) { |
| 103 | + apr_sha1_update(&sha1, buffer, readBytes); |
| 104 | + } |
| 105 | + apr_sha1_final(digest.chr, &sha1); |
| 106 | + |
| 107 | + /* Print out the SHA1 digest */ |
| 108 | + ap_rputs("<b>SHA1: </b><code>", r); |
| 109 | + for (n = 0; n < APR_SHA1_DIGESTSIZE/4; n++) { |
| 110 | + ap_rprintf(r, "%08x", digest.num[n]); |
| 111 | + } |
| 112 | + ap_rputs("</code>", r); |
| 113 | + |
| 114 | + /* Print a link to the MD5 version */ |
| 115 | + ap_rputs("<br/><a href='?digest=md5'>View the MD5 hash instead</a>", r); |
| 116 | + } |
| 117 | + apr_file_close(file); |
| 118 | + |
| 119 | + } |
| 120 | + /* Let the server know that we responded to this request. */ |
| 121 | + return OK; |
| 122 | +} |
| 123 | + |
| 124 | +static void register_hooks(apr_pool_t *pool) |
| 125 | +{ |
| 126 | + /* Create a hook in the request handler, so we get called when a request arrives */ |
| 127 | + ap_hook_handler(example_handler, NULL, NULL, APR_HOOK_LAST); |
| 128 | +} |
| 129 | + |
| 130 | +AP_DECLARE_MODULE(example) = |
| 131 | +{ |
| 132 | + STANDARD20_MODULE_STUFF, |
| 133 | + NULL, |
| 134 | + NULL, |
| 135 | + NULL, |
| 136 | + NULL, |
| 137 | + NULL, |
| 138 | + register_hooks /* Our hook registering function */ |
| 139 | +}; |
0 commit comments