void uh_chunk_vprintf(struct client *cl, const char *format, va_list arg) { char buf[256]; va_list arg2; int len; if (cl->state == CLIENT_STATE_CLEANUP) return; uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); if (!uh_use_chunked(cl)) { ustream_vprintf(cl->us, format, arg); return; } va_copy(arg2, arg); len = vsnprintf(buf, sizeof(buf), format, arg2); va_end(arg2); ustream_printf(cl->us, "%X\r\n", len); if (len < sizeof(buf)) ustream_write(cl->us, buf, len, true); else ustream_vprintf(cl->us, format, arg); ustream_printf(cl->us, "\r\n", len); }
static void uh_file_response_ok_hdrs(struct client *cl, struct stat *s) { char buf[128]; if (s) { ustream_printf(cl->us, "ETag: %s\r\n", make_file_etag(s, buf, sizeof(buf))); ustream_printf(cl->us, "Last-Modified: %s\r\n", uh_file_unix2date(s->st_mtime, buf, sizeof(buf))); } ustream_printf(cl->us, "Date: %s\r\n", uh_file_unix2date(time(NULL), buf, sizeof(buf))); }
void uh_chunk_write(struct client *cl, const void *data, int len) { bool chunked = uh_use_chunked(cl); if (cl->state == CLIENT_STATE_CLEANUP) return; uloop_timeout_set(&cl->timeout, conf.network_timeout * 1000); if (chunked) ustream_printf(cl->us, "%X\r\n", len); ustream_write(cl->us, data, len, true); if (chunked) ustream_printf(cl->us, "\r\n", len); }
static void proc_handle_header_end(struct relay *r) { struct client *cl = r->cl; struct dispatch_proc *p = &cl->dispatch.proc; struct blob_attr *cur; int rem; uloop_timeout_cancel(&p->timeout); uh_http_header(cl, cl->dispatch.proc.status_code, cl->dispatch.proc.status_msg); blob_for_each_attr(cur, cl->dispatch.proc.hdr.head, rem) ustream_printf(cl->us, "%s: %s\r\n", blobmsg_name(cur), blobmsg_data(cur)); ustream_printf(cl->us, "\r\n"); if (cl->request.method == UH_HTTP_MSG_HEAD) r->skip_data = true; }
void uh_chunk_eof(struct client *cl) { if (!uh_use_chunked(cl)) return; if (cl->state == CLIENT_STATE_CLEANUP) return; ustream_printf(cl->us, "0\r\n\r\n"); }
static void uh_file_data(struct client *cl, struct path_info *pi, int fd) { /* test preconditions */ if (!uh_file_if_modified_since(cl, &pi->stat) || !uh_file_if_match(cl, &pi->stat) || !uh_file_if_range(cl, &pi->stat) || !uh_file_if_unmodified_since(cl, &pi->stat) || !uh_file_if_none_match(cl, &pi->stat)) { ustream_printf(cl->us, "Content-Length: 0\r\n"); ustream_printf(cl->us, "\r\n"); request_done(cl); close(fd); return; } /* write status */ uh_file_response_200(cl, &pi->stat); ustream_printf(cl->us, "Content-Type: %s\r\n", file_mime_lookup(pi->name)); ustream_printf(cl->us, "Content-Length: %i\r\n\r\n", pi->stat.st_size); /* Stop if this is a header only request */ if (cl->request.method == UH_HTTP_MSG_HEAD) { request_done(cl); close(fd); return; } cl->dispatch.file.fd = fd; cl->dispatch.write_cb = file_write_cb; cl->dispatch.free = uh_file_free; cl->dispatch.close_fds = uh_file_free; file_write_cb(cl); }
static void uh_file_dirlist(struct client *cl, struct path_info *pi) { struct dirent **files = NULL; int count = 0; uh_file_response_200(cl, NULL); ustream_printf(cl->us, "Content-Type: text/html\r\n\r\n"); uh_chunk_printf(cl, "<html><head><title>Index of %s</title></head>" "<body><h1>Index of %s</h1><hr /><ol>", pi->name, pi->name); count = scandir(pi->phys, &files, NULL, dirent_cmp); if (count > 0) { strcpy(uh_buf, pi->phys); list_entries(cl, files, count, pi->name, uh_buf); } free(files); uh_chunk_printf(cl, "</ol><hr /></body></html>"); request_done(cl); }
/** * Given a url this functions tries to find the physical path on the server. * @cl the client that made the request * @url the requested URL * @return NULL on error */ static struct path_info *path_lookup(struct client *cl, const char *url) { static char path_phys[PATH_MAX]; static char path_info[PATH_MAX]; static struct path_info p; int docroot_len = strlen(DOCUMENT_ROOT); char *pathptr = NULL; bool slash; int i = 0; int len; struct stat s; /* Return NULL when the URL is undefined */ if (url == NULL) return NULL; memset(&p, 0, sizeof(p)); path_phys[0] = 0; path_info[0] = 0; /* Start the canonical path with the document root */ strcpy(uh_buf, DOCUMENT_ROOT); /* Separate query string from url */ if ((pathptr = strchr(url, '?')) != NULL) { p.query = pathptr[1] ? pathptr + 1 : NULL; /* URL decode component without query */ if (pathptr > url) { if (uh_urldecode(&uh_buf[docroot_len], sizeof(uh_buf) - docroot_len - 1, url, pathptr - url ) < 0) return NULL; } } /* Decode the full url when there is no querystring */ else if (uh_urldecode(&uh_buf[docroot_len], sizeof(uh_buf) - docroot_len - 1, url, strlen(url) ) < 0) return NULL; /* Create canonical path */ len = strlen(uh_buf); slash = len && uh_buf[len - 1] == '/'; len = min(len, sizeof(path_phys) - 1); for (i = len; i >= 0; i--) { char ch = uh_buf[i]; bool exists; if (ch != 0 && ch != '/') continue; uh_buf[i] = 0; exists = !!canonpath(uh_buf, path_phys); uh_buf[i] = ch; if (!exists) continue; /* Test the current path */ if (stat(path_phys, &p.stat)) continue; snprintf(path_info, sizeof(path_info), "%s", uh_buf + i); break; } /* Check whether found path is within docroot */ if (strncmp(path_phys, DOCUMENT_ROOT, docroot_len) != 0 || (path_phys[docroot_len] != 0 && path_phys[docroot_len] != '/')){ return NULL; } /* Check if the found file is a regular file */ if (p.stat.st_mode & S_IFREG) { p.root = DOCUMENT_ROOT; p.phys = path_phys; p.name = &path_phys[docroot_len]; p.info = path_info[0] ? path_info : NULL; return &p; } /* Make sure it is not a directory */ if (!(p.stat.st_mode & S_IFDIR)){ return NULL; } if (path_info[0]){ return NULL; } pathptr = path_phys + strlen(path_phys); /* ensure trailing slash */ if (pathptr[-1] != '/') { pathptr[0] = '/'; pathptr[1] = 0; pathptr++; } /* if requested url resolves to a directory and a trailing slash is missing in the request url, redirect the client to the same url with trailing slash appended */ if (!slash) { write_http_header(cl, 302, "Found"); ustream_printf(cl->us, "Content-Length: 0\r\n"); ustream_printf(cl->us, "Location: %s%s%s\r\n\r\n", &path_phys[docroot_len], p.query ? "?" : "", p.query ? p.query : ""); request_done(cl); p.redirected = 1; return &p; } /* Check if the folder contains an index file */ len = path_phys + sizeof(path_phys) - pathptr - 1; if(strlen(INDEX_FILE) <= len){ strcpy(pathptr, INDEX_FILE); if (!stat(path_phys, &s) && (s.st_mode & S_IFREG)) { memcpy(&p.stat, &s, sizeof(p.stat)); } else { /* Stop when strcpy is not needed */ *pathptr = 0; } } p.root = DOCUMENT_ROOT; p.phys = path_phys; p.name = &path_phys[docroot_len]; return p.phys ? &p : NULL; }