static void handle_propfind(struct mg_connection *conn, const char *path, struct file *filep) { const char *depth = mg_get_header(conn, "Depth"); conn->must_close = 1; conn->status_code = 207; mg_printf(conn, "HTTP/1.1 207 Multi-Status\r\n" "Connection: close\r\n" "Content-Type: text/xml; charset=utf-8\r\n\r\n"); conn->num_bytes_sent += mg_printf(conn, "<?xml version=\"1.0\" encoding=\"utf-8\"?>" "<d:multistatus xmlns:d='DAV:'>\n"); // Print properties for the requested resource itself print_props(conn, conn->request_info.uri, filep); // If it is a directory, print directory entries too if Depth is not 0 if (filep->is_directory && !mg_strcasecmp(conn->ctx->config[ENABLE_DIRECTORY_LISTING], "yes") && (depth == NULL || strcmp(depth, "0") != 0)) { scan_directory(conn, path, conn, &print_dav_dir_entry); } conn->num_bytes_sent += mg_printf(conn, "%s\n", "</d:multistatus>"); }
// Check the user's password, return 1 if OK static int check_password(const char *method, const char *ha1, const char *uri, const char *nonce, const char *nc, const char *cnonce, const char *qop, const char *response) { char ha2[32 + 1], expected_response[32 + 1]; // Some of the parameters may be NULL if (method == NULL || nonce == NULL || nc == NULL || cnonce == NULL || qop == NULL || response == NULL) { return 0; } // NOTE(lsm): due to a bug in MSIE, we do not compare the URI // TODO(lsm): check for authentication timeout if (// strcmp(dig->uri, c->ouri) != 0 || strlen(response) != 32 // || now - strtoul(dig->nonce, NULL, 10) > 3600 ) { return 0; } mg_md5(ha2, method, ":", uri, NULL); mg_md5(expected_response, ha1, ":", nonce, ":", nc, ":", cnonce, ":", qop, ":", ha2, NULL); return mg_strcasecmp(response, expected_response) == 0; }
// Return HTTP header value, or NULL if not found. static const char *get_header(const struct mg_request_info *ri, const char *name) { int i; for (i = 0; i < ri->num_headers; i++) if (!mg_strcasecmp(name, ri->http_headers[i].name)) return ri->http_headers[i].value; return NULL; }
static void test_mg_fetch(void) { static const char *options[] = { "document_root", ".", "listening_ports", UNUSED_PORT, NULL, }; char buf[2000], buf2[2000]; int n, length; struct mg_context *ctx; struct mg_request_info ri; const char *tmp_file = "temporary_file_name_for_unit_test.txt"; struct file file; FILE *fp; ASSERT((ctx = mg_start(event_handler, NULL, options)) != NULL); // Failed fetch, pass invalid URL ASSERT(mg_fetch(ctx, "localhost", tmp_file, buf, sizeof(buf), &ri) == NULL); ASSERT(mg_fetch(ctx, "localhost:" UNUSED_PORT, tmp_file, buf, sizeof(buf), &ri) == NULL); ASSERT(mg_fetch(ctx, "http://$$$.$$$", tmp_file, buf, sizeof(buf), &ri) == NULL); // Failed fetch, pass invalid file name ASSERT(mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data", "/this/file/must/not/exist/ever", buf, sizeof(buf), &ri) == NULL); // Successful fetch ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/data", tmp_file, buf, sizeof(buf), &ri)) != NULL); ASSERT(ri.num_headers == 2); ASSERT(!strcmp(ri.request_method, "HTTP/1.1")); ASSERT(!strcmp(ri.uri, "200")); ASSERT(!strcmp(ri.http_version, "OK")); ASSERT((length = ftell(fp)) == (int) strlen(fetch_data)); fseek(fp, 0, SEEK_SET); ASSERT(fread(buf2, 1, length, fp) == (size_t) length); ASSERT(memcmp(buf2, fetch_data, length) == 0); fclose(fp); // Fetch big file, mongoose.c ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/mongoose.c", tmp_file, buf, sizeof(buf), &ri)) != NULL); ASSERT(mg_stat(fc(ctx), "mongoose.c", &file)); ASSERT(file.size == ftell(fp)); ASSERT(!strcmp(ri.request_method, "HTTP/1.1")); // Fetch nonexistent file, /blah ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/boo", tmp_file, buf, sizeof(buf), &ri)) != NULL); ASSERT(!mg_strcasecmp(ri.uri, "404")); fclose(fp); // Fetch existing inmemory file ASSERT((fp = mg_fetch(ctx, "http://localhost:" UNUSED_PORT "/blah", tmp_file, buf, sizeof(buf), &ri)) != NULL); ASSERT(!mg_strcasecmp(ri.uri, "200")); n = ftell(fp); fseek(fp, 0, SEEK_SET); printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2); n = fread(buf2, 1, n, fp); printf("%s %d %d [%.*s]\n", __func__, n, (int) feof(fp), n, buf2); ASSERT((size_t) ftell(fp) == (size_t) strlen(inmemory_file_data)); ASSERT(!memcmp(inmemory_file_data, buf2, ftell(fp))); fclose(fp); remove(tmp_file); mg_stop(ctx); }