int websFormHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) { sym_t *sp; char_t formBuf[FNAMESIZE]; char_t *cp, *formName; int (*fn)(void *sock, char_t *path, char_t *args); a_assert(websValid(wp)); a_assert(url && *url); a_assert(path && *path == '/'); websStats.formHits++; /* * Extract the form name */ gstrncpy(formBuf, path, TSZ(formBuf)); if ((formName = gstrchr(&formBuf[1], '/')) == NULL) { websError(wp, 200, T("Missing form name")); return 1; } formName++; if ((cp = gstrchr(formName, '/')) != NULL) { *cp = '\0'; } /* * Lookup the C form function first and then try tcl (no javascript support * yet). */ sp = symLookup(formSymtab, formName); if (sp == NULL) { websError(wp, 200, T("Form %s is not defined"), formName); } else { fn = (int (*)(void *, char_t *, char_t *)) sp->content.value.integer; a_assert(fn); if (fn) { /* * For good practice, forms must call websDone() */ (*fn)((void*) wp, formName, query); /* * Remove the test to force websDone, since this prevents * the server "push" from a form> */ #if 0 /* push */ if (websValid(wp)) { websError(wp, 200, T("Form didn't call websDone")); } #endif /* push */ } } return 1; }
void ej_exec_milkfish_service(webs_t wp, int argc, char_t ** argv) { FILE *fp; char line[254]; char *request; #ifdef FASTWEB ejArgs(argc, argv, "%s", &request); #else if (ejArgs(argc, argv, "%s", &request) < 1) { websError(wp, 400, "Insufficient args\n"); } #endif if ((fp = popen(request, "r"))) { while (fgets(line, sizeof(line), fp) != NULL) { websWrite(wp, line); websWrite(wp, "<br>"); } pclose(fp); } return; }
/* Do output back to the browser in the background. This is a socket write handler. This bypasses the output buffer and writes directly to the socket. */ static void fileWriteEvent(Webs *wp) { char *buf; ssize len, wrote; assert(wp); assert(websValid(wp)); /* Note: websWriteSocket may return less than we wanted. It will return -1 on a socket error. */ if ((buf = walloc(ME_GOAHEAD_LIMIT_BUFFER)) == NULL) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Cannot get memory"); return; } /* OPT - we could potentially save this buffer so that on short-writes, it does not need to be re-read. */ while ((len = websPageReadData(wp, buf, ME_GOAHEAD_LIMIT_BUFFER)) > 0) { if ((wrote = websWriteSocket(wp, buf, len)) < 0) { break; } if (wrote != len) { websPageSeek(wp, - (len - wrote), SEEK_CUR); break; } } wfree(buf); if (len <= 0) { websDone(wp); } }
int ej_get_isp_list(int eid, webs_t wp, int argc, char_t **argv){ char *name; FILE* fpIsp; char bufIsp[512]; if (ejArgs(argc, argv, "%s", &name) < 1) { websError(wp, 400, "Insufficient args\n"); return -1; } fpIsp = fopen(name,"r"); if (fpIsp != NULL) { // read out UTF-8 3 bytes header fread(bufIsp,3,1,fpIsp); while(!feof(fpIsp)) { char* ret_fgets; ret_fgets = fgets(bufIsp,sizeof(bufIsp),fpIsp); if (ret_fgets != NULL) { websWrite(wp, bufIsp); websWrite(wp, "\n"); } } fclose(fpIsp); } return 0; }
PUBLIC bool websAuthenticate(Webs *wp) { WebsRoute *route; char *username; int cached; assert(wp); assert(wp->route); route = wp->route; if (!route || !route->authType || autoLogin) { /* Authentication not required */ return 1; } cached = 0; if (wp->cookie && websGetSession(wp, 0) != 0) { /* Retrieve authentication state from the session storage. Faster than re-authenticating. */ if ((username = (char*) websGetSessionVar(wp, WEBS_SESSION_USERNAME, 0)) != 0) { cached = 1; wfree(wp->username); wp->username = sclone(username); } } if (!cached) { if (wp->authType && !smatch(wp->authType, route->authType)) { websError(wp, HTTP_CODE_UNAUTHORIZED, "Access denied. Wrong authentication protocol type."); return 0; } if (wp->authDetails && route->parseAuth) { if (!(route->parseAuth)(wp)) { wp->username = 0; } } if (!wp->username || !*wp->username) { if (route->askLogin) { (route->askLogin)(wp); } websRedirectByStatus(wp, HTTP_CODE_UNAUTHORIZED); return 0; } if (!(route->verify)(wp)) { if (route->askLogin) { (route->askLogin)(wp); } websRedirectByStatus(wp, HTTP_CODE_UNAUTHORIZED); return 0; } /* Store authentication state and user in session storage */ if (websGetSession(wp, 1) != 0) { websSetSessionVar(wp, WEBS_SESSION_USERNAME, wp->username); } } return 1; }
int websUrlHandlerRequest(webs_t wp) { websUrlHandlerType *sp; int i, first; a_assert(websValid(wp)); trace(8, T("%s %d %s\n"),__FILE__,__LINE__,__FUNCTION__); /* * Delete the socket handler as we don't want to start reading any * data on the connection as it may be for the next pipelined HTTP/1.1 * request if using Keep Alive */ socketDeleteHandler(wp->sid); wp->state = WEBS_PROCESSING; websStats.handlerHits++; websSetRequestPath(wp, websGetDefaultDir(), NULL); /* * Eliminate security hole */ websCondenseMultipleChars(wp->path, '/'); websCondenseMultipleChars(wp->url, '/'); /* * We loop over each handler in order till one accepts the request. * The security handler will handle the request if access is NOT allowed. */ first = 1; for (i = 0; i < websUrlHandlerMax; i++) { sp = &websUrlHandler[i]; if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) { if (first) { websSetEnv(wp); first = 0; } if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg, wp->url, wp->path, wp->query)) { return 1; } if (!websValid(wp)) { trace(0, T("webs: handler %s called websDone, but didn't return 1\n"), sp->urlPrefix); return 1; } } } /* * If no handler processed the request, then return an error. Note: It is * the handlers responsibility to call websDone */ if (i >= websUrlHandlerMax) { websError(wp, 200, T("No handler for this URL %s"), wp->url); } return 0; }
/* Any entry in the cgiList need to be checked to see if it has completed, and if so, process its output and clean up. Return time till next poll. */ WebsTime websCgiPoll() { Webs *wp; Cgi *cgip; char **ep; int cid, nTries; for (cid = 0; cid < cgiMax; cid++) { if ((cgip = cgiList[cid]) != NULL) { wp = cgip->wp; websCgiGatherOutput(cgip); if (checkCgi(cgip->handle) == 0) { /* We get here if the CGI process has terminated. Clean up. */ for (nTries = 0; (cgip->fplacemark == 0) && (nTries < 100); nTries++) { websCgiGatherOutput(cgip); /* There are some cases when we detect app exit before the file is ready. */ if (cgip->fplacemark == 0) { #if WINDOWS Sleep(10); #endif } } if (cgip->fplacemark == 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "CGI generated no output"); } else { trace(5, "cgi: Request complete - calling websDone"); websDone(wp); } /* Remove the temporary re-direction files */ unlink(cgip->stdIn); unlink(cgip->stdOut); /* Free all the memory buffers pointed to by cgip. The stdin file name (wp->cgiStdin) gets freed as part of websFree(). */ cgiMax = wfreeHandle(&cgiList, cid); for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) { wfree(*ep); } wfree(cgip->cgiPath); wfree(cgip->argp); wfree(cgip->envp); wfree(cgip->stdOut); wfree(cgip); websPump(wp); } } } return cgiMax ? 10 : MAXINT; }
static int aspTest(int eid, webs_t wp, int argc, char_t **argv) { char_t *name, *address; if (ejArgs(argc, argv, T("%s %s"), &name, &address) < 2) { websError(wp, 400, T("Insufficient args\n")); return -1; } return websWrite(wp, T("Name: %s, Address %s"), name, address); }
static void logoutServiceProc(Webs *wp) { assure(wp); websRemoveSessionVar(wp, WEBS_SESSION_USERNAME); if (smatch(wp->authType, "basic") || smatch(wp->authType, "digest")) { websError(wp, HTTP_CODE_UNAUTHORIZED, "Logged out."); return; } websRedirectByStatus(wp, HTTP_CODE_OK); }
/* Parse the form variables: name, address and echo back */ static int aspTest(int eid, Webs *wp, int argc, char **argv) { char *name, *address; if (jsArgs(argc, argv, "%s %s", &name, &address) < 2) { websError(wp, 400, "Insufficient args\n"); return -1; } return (int) websWrite(wp, "Name: %s, Address %s", name, address); }
static void websDefaultWriteEvent(webs_t wp) { int len, wrote, flags, bytes, written; char *buf; a_assert(websValid(wp)); flags = websGetRequestFlags(wp); websSetTimeMark(wp); wrote = bytes = 0; written = websGetRequestWritten(wp); /* * We only do this for non-ASP documents */ if ( !(flags & WEBS_ASP)) { bytes = websGetRequestBytes(wp); /* * Note: websWriteDataNonBlock may return less than we wanted. It will * return -1 on a socket error */ if ((buf = balloc(B_L, PAGE_READ_BUFSIZE)) == NULL) { websError(wp, 200, T("Can't get memory")); } else { while ((len = websPageReadData(wp, buf, PAGE_READ_BUFSIZE)) > 0) { if ((wrote = websWriteDataNonBlock(wp, buf, len)) < 0) { break; } written += wrote; if (wrote != len) { websPageSeek(wp, - (len - wrote)); break; } } /* * Safety. If we are at EOF, we must be done */ if (len == 0) { a_assert(written >= bytes); written = bytes; } bfree(B_L, buf); } } /* * We're done if an error, or all bytes output */ websSetRequestWritten(wp, written); if (wrote < 0 || written >= bytes) { websDone(wp, 200); } }
void ej_get_url(webs_t wp, int argc, char_t ** argv) { char *type; if (ejArgs(argc, argv, "%s", &type) < 1) { websError(wp, 400, "Insufficient args\n"); return; } websWrite(wp, "%s", "Invalid argument\n"); }
PUBLIC bool websLogoutUser(Webs *wp) { assert(wp); websRemoveSessionVar(wp, WEBS_SESSION_USERNAME); if (smatch(wp->authType, "basic") || smatch(wp->authType, "digest")) { websError(wp, HTTP_CODE_UNAUTHORIZED, "Logged out."); return 0; } websRedirectByStatus(wp, HTTP_CODE_OK); return 1; }
/* Process an action request. Returns 1 always to indicate it handled the URL */ static bool actionHandler(Webs *wp) { WebsKey *sp; char actionBuf[BIT_GOAHEAD_LIMIT_URI + 1]; char *cp, *actionName; WebsAction fn; assert(websValid(wp)); assert(actionTable >= 0); /* Extract the action name */ scopy(actionBuf, sizeof(actionBuf), wp->path); if ((actionName = strchr(&actionBuf[1], '/')) == NULL) { websError(wp, HTTP_CODE_NOT_FOUND, "Missing action name"); return 1; } actionName++; if ((cp = strchr(actionName, '/')) != NULL) { *cp = '\0'; } /* Lookup the C action function first and then try tcl (no javascript support yet). */ sp = hashLookup(actionTable, actionName); if (sp == NULL) { websError(wp, HTTP_CODE_NOT_FOUND, "Action %s is not defined", actionName); } else { fn = (WebsAction) sp->content.value.symbol; assert(fn); if (fn) { #if BIT_GOAHEAD_LEGACY (*((WebsProc) fn))((void*) wp, actionName, wp->query); #else (*fn)((void*) wp); #endif } } return 1; }
/* Process an action request. Returns 1 always to indicate it handled the URL */ static bool actionHandler(Webs *wp) { WebsKey *sp; char formBuf[BIT_LIMIT_FILENAME]; char *cp, *formName; WebsAction fn; assure(websValid(wp)); assure(formSymtab >= 0); /* Extract the form name */ scopy(formBuf, sizeof(formBuf), wp->path); if ((formName = strchr(&formBuf[1], '/')) == NULL) { websError(wp, HTTP_CODE_NOT_FOUND, "Missing form name"); return 1; } formName++; if ((cp = strchr(formName, '/')) != NULL) { *cp = '\0'; } /* Lookup the C form function first and then try tcl (no javascript support yet). */ sp = hashLookup(formSymtab, formName); if (sp == NULL) { websError(wp, HTTP_CODE_NOT_FOUND, "Action %s is not defined", formName); } else { fn = (WebsAction) sp->content.value.symbol; assure(fn); if (fn) { #if BIT_LEGACY (*fn)((void*) wp, formName, wp->query); #else (*fn)((void*) wp); #endif } } return 1; }
PUBLIC int websProcessPutData(Webs *wp) { ssize nbytes; assert(wp); assert(wp->putfd >= 0); assert(wp->input.buf); nbytes = bufLen(&wp->input); wp->putLen += nbytes; if (wp->putLen > ME_GOAHEAD_LIMIT_PUT) { websError(wp, HTTP_CODE_REQUEST_TOO_LARGE | WEBS_CLOSE, "Put file too large"); return -1; } if (write(wp->putfd, wp->input.servp, (int) nbytes) != nbytes) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR | WEBS_CLOSE, "Cannot write to file"); return -1; } websConsumeInput(wp, nbytes); return 0; }
PUBLIC int websProcessCgiData(Webs *wp) { ssize nbytes; nbytes = bufLen(&wp->input); trace(5, "cgi: write %d bytes to CGI program", nbytes); if (write(wp->cgifd, wp->input.servp, (int) nbytes) != nbytes) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR| WEBS_CLOSE, "Can't write to CGI gateway"); return -1; } websConsumeInput(wp, nbytes); trace(5, "cgi: write %d bytes to CGI program", nbytes); return 0; }
static int writeToFile(Webs *wp, char *data, ssize len) { WebsUpload *file; ssize rc; file = wp->currentFile; if ((file->size + len) > BIT_GOAHEAD_LIMIT_UPLOAD) { websError(wp, HTTP_CODE_REQUEST_TOO_LARGE, "Uploaded file exceeds maximum %d", (int) BIT_GOAHEAD_LIMIT_UPLOAD); return -1; } if (len > 0) { /* File upload. Write the file data. */ if ((rc = write(wp->upfd, data, (int) len)) != len) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't write to upload temp file %s, rc %d", wp->uploadTmp, rc); return -1; } file->size += len; trace(7, "uploadFilter: Wrote %d bytes to %s", len, wp->uploadTmp); } return 0; }
static void processContentBoundary(Webs *wp, char *line) { /* Expecting a multipart boundary string */ if (strncmp(wp->boundary, line, wp->boundaryLen) != 0) { websError(wp, HTTP_CODE_BAD_REQUEST, "Bad upload state. Incomplete boundary"); } else if (line[wp->boundaryLen] && strcmp(&line[wp->boundaryLen], "--") == 0) { wp->uploadState = UPLOAD_CONTENT_END; } else { wp->uploadState = UPLOAD_CONTENT_HEADER; } }
static int initUpload(Webs *wp) { char *boundary; if (wp->uploadState == 0) { wp->uploadState = UPLOAD_BOUNDARY; if ((boundary = strstr(wp->contentType, "boundary=")) != 0) { boundary += 9; wp->boundary = sfmt("--%s", boundary); wp->boundaryLen = strlen(wp->boundary); } if (wp->boundaryLen == 0 || *wp->boundary == '\0') { websError(wp, HTTP_CODE_BAD_REQUEST, "Bad boundary"); return -1; } websSetVar(wp, "UPLOAD_DIR", uploadDir); wp->files = hashCreate(11); } return 0; }
void ej_get_clone_mac(webs_t wp, int argc, char_t ** argv) { char *c; int mac, which; int dofree = 0; #ifdef FASTWEB ejArgs(argc, argv, "%d", &which); #else if (ejArgs(argc, argv, "%d", &which) < 1) { websError(wp, 400, "Insufficient args\n"); } #endif if (nvram_match("clone_wan_mac", "1")) c = nvram_safe_get("http_client_mac"); else { if (nvram_match("def_hwaddr", "00:00:00:00:00:00")) { if (nvram_match("port_swap", "1")) c = strdup(nvram_safe_get("et1macaddr")); else c = strdup(nvram_safe_get("et0macaddr")); if (c) { MAC_ADD(c); dofree = 1; } } else c = nvram_safe_get("def_hwaddr"); } if (c) { mac = get_single_mac(c, which); websWrite(wp, "%02X", mac); if (dofree) free(c); } else websWrite(wp, "00"); }
int ej_do_print_end(int eid, webs_t wp, int argc, char_t ** argv) { char *str; int level, cur_level; if (ejArgs(argc, argv, "%s", &str) < 1) { websError(wp, 400, "Insufficient args\n"); return -1; } sscanf(str, "EZP_PRODUCT_LEVEL_%d", &level); str = nvram_safe_get("prod_level"); if (!*str) cur_level = 1; cur_level = atoi(str); if (cur_level < level) { ej_print = 1; } return 0; }
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) { websStatType sbuf; char_t *lpath, *tmp, *date; int bytes, flags, nchars; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path); a_assert(query); /* * Validate the URL and ensure that ".."s don't give access to unwanted files */ flags = websGetRequestFlags(wp); if (websValidateUrl(wp, path) < 0) { websError(wp, 500, T("Invalid URL %s"), url); return 1; } lpath = websGetRequestLpath(wp); nchars = gstrlen(lpath) - 1; if (lpath[nchars] == '/' || lpath[nchars] == '\\') { lpath[nchars] = '\0'; } /* * If the file is a directory, redirect using the nominated default page */ if (websPageIsDirectory(lpath)) { nchars = gstrlen(path); if (path[nchars-1] == '/' || path[nchars-1] == '\\') { path[--nchars] = '\0'; } nchars += gstrlen(websDefaultPage) + 2; fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage); websRedirect(wp, tmp); bfreeSafe(B_L, tmp); return 1; } /* * Open the document. Stat for later use. */ if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY, 0666) < 0) { websError(wp, 400, T("Cannot open URL <b>%s</b>"), url); return 1; } if (websPageStat(wp, lpath, path, &sbuf) < 0) { websError(wp, 400, T("Cannot stat page for URL <b>%s</b>"), url); return 1; } /* * If the page has not been modified since the user last received it and it * is not dynamically generated each time (ASP), then optimize request by * sending a 304 Use local copy response */ websStats.localHits++; #ifdef WEBS_IF_MODIFIED_SUPPORT if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) { if (sbuf.mtime <= wp->since) { websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n")); /* * by license terms the following line of code must * not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); if (flags & WEBS_KEEP_ALIVE) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE); websDone(wp, 304); return 1; } } #endif /* * Output the normal HTTP response header */ if ((date = websGetDateString(NULL)) != NULL) { websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date); /* * By license terms the following line of code must not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); bfree(B_L, date); } flags |= WEBS_HEADER_DONE; /* * If this is an ASP request, ensure the remote browser doesn't cache it. * Send back both HTTP/1.0 and HTTP/1.1 cache control directives */ if (flags & WEBS_ASP) { bytes = 0; websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n")); } else { if ((date = websGetDateString(&sbuf)) != NULL) { websWrite(wp, T("Last-modified: %s\r\n"), date); bfree(B_L, date); } bytes = sbuf.size; } if (bytes) { websWrite(wp, T("Content-length: %d\r\n"), bytes); websSetRequestBytes(wp, bytes); } websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp)); if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); /* * All done if the browser did a HEAD request */ if (flags & WEBS_HEAD_REQUEST) { websDone(wp, 200); return 1; } /* * Evaluate ASP requests */ if (flags & WEBS_ASP) { if (websAspRequest(wp, lpath) < 0) { return 1; } websDone(wp, 200); return 1; } #ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { websDefaultWriteEvent(wp); } else { websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); } #else /* * For normal web documents, return the data via background write */ websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); #endif return 1; }
int websUrlHandlerRequest(webs_t wp) { websUrlHandlerType *sp; int i, first; a_assert(websValid(wp)); /* * Delete the socket handler as we don't want to start reading any * data on the connection as it may be for the next pipelined HTTP/1.1 * request if using Keep Alive */ socketDeleteHandler(wp->sid); wp->state = WEBS_PROCESSING; websStats.handlerHits++; websSetRequestPath(wp, websGetDefaultDir(), NULL); /* * Eliminate security hole */ websCondenseMultipleChars(wp->path, '/'); websCondenseMultipleChars(wp->url, '/'); /* Fix by Luigi Auriemma 19 Jan 2004 */ /* http://aluigi.altervista.org/adv/goahead-adv2.txt */ if ((wp->path[0] != '/') || strchr(wp->path, '\\')) { websError(wp, 400, T("Bad request")); return 0; } /* * We loop over each handler in order till one accepts the request. * The security handler will handle the request if access is NOT allowed. */ first = 1; for (i = 0; i < websUrlHandlerMax; i++) { sp = &websUrlHandler[i]; if (sp->handler && gstrncmp(sp->urlPrefix, wp->path, sp->len) == 0) { if (first) { websSetEnv(wp); first = 0; } if ((*sp->handler)(wp, sp->urlPrefix, sp->webDir, sp->arg, wp->url, wp->path, wp->query)) { return 1; } if (!websValid(wp)) { trace(0, T("webs: handler %s called websDone, but didn't return 1\n"), sp->urlPrefix); return 1; } } } /* * If no handler processed the request, then return an error. Note: It is * the handlers responsibility to call websDone */ if (i >= websUrlHandlerMax) { /* * 13 Mar 03 BgP * preventing a cross-site scripting exploit websError(wp, 200, T("No handler for this URL %s"), wp->url); */ websError(wp, 200, T("No handler for this URL")); } return 0; }
/* Serve static files */ static bool fileHandler(Webs *wp) { WebsFileInfo info; char *tmp, *date; ssize nchars; int code; assert(websValid(wp)); assert(wp->method); assert(wp->filename && wp->filename[0]); #if !ME_ROM if (smatch(wp->method, "DELETE")) { if (unlink(wp->filename) < 0) { websError(wp, HTTP_CODE_NOT_FOUND, "Cannot delete the URI"); } else { /* No content */ websResponse(wp, 204, 0); } } else if (smatch(wp->method, "PUT")) { /* Code is already set for us by processContent() */ websResponse(wp, wp->code, 0); } else #endif /* !ME_ROM */ { /* If the file is a directory, redirect using the nominated default page */ if (websPageIsDirectory(wp)) { nchars = strlen(wp->path); if (wp->path[nchars - 1] == '/' || wp->path[nchars - 1] == '\\') { wp->path[--nchars] = '\0'; } tmp = sfmt("%s/%s", wp->path, websIndex); websRedirect(wp, tmp); wfree(tmp); return 1; } if (websPageOpen(wp, O_RDONLY | O_BINARY, 0666) < 0) { #if ME_DEBUG if (wp->referrer) { trace(1, "From %s", wp->referrer); } #endif websError(wp, HTTP_CODE_NOT_FOUND, "Cannot open document for: %s", wp->path); return 1; } if (websPageStat(wp, &info) < 0) { websError(wp, HTTP_CODE_NOT_FOUND, "Cannot stat page for URL"); return 1; } code = 200; if (wp->since && info.mtime <= wp->since) { code = 304; info.size = 0; } websSetStatus(wp, code); websWriteHeaders(wp, info.size, 0); if ((date = websGetDateString(&info)) != NULL) { websWriteHeader(wp, "Last-Modified", "%s", date); wfree(date); } websWriteEndHeaders(wp); /* All done if the browser did a HEAD request */ if (smatch(wp->method, "HEAD")) { websDone(wp); return 1; } if (info.size > 0) { websSetBackgroundWriter(wp, fileWriteEvent); } else { websDone(wp); } } return 1; }
static int processUploadHeader(Webs *wp, char *line) { WebsUpload *file; char *key, *headerTok, *rest, *nextPair, *value; if (line[0] == '\0') { wp->uploadState = UPLOAD_CONTENT_DATA; return 0; } trace(7, "Header line: %s", line); headerTok = line; stok(line, ": ", &rest); if (scaselesscmp(headerTok, "Content-Disposition") == 0) { /* The content disposition header describes either a form variable or an uploaded file. Content-Disposition: form-data; name="field1" >>blank line Field Data ---boundary Content-Disposition: form-data; name="field1" filename="user.file" >>blank line File data ---boundary */ key = rest; wp->uploadVar = wp->clientFilename = 0; while (key && stok(key, ";\r\n", &nextPair)) { key = strim(key, " ", WEBS_TRIM_BOTH); stok(key, "= ", &value); value = strim(value, "\"", WEBS_TRIM_BOTH); if (scaselesscmp(key, "form-data") == 0) { /* Nothing to do */ } else if (scaselesscmp(key, "name") == 0) { wp->uploadVar = sclone(value); } else if (scaselesscmp(key, "filename") == 0) { if (wp->uploadVar == 0) { websError(wp, HTTP_CODE_BAD_REQUEST, "Bad upload state. Missing name field"); return -1; } wp->clientFilename = sclone(value); /* Create the file to hold the uploaded data */ if ((wp->uploadTmp = websTempFile(uploadDir, "tmp")) == 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't create upload temp file %s. Check upload temp dir %s", wp->uploadTmp, uploadDir); return -1; } trace(5, "File upload of: %s stored as %s", wp->clientFilename, wp->uploadTmp); if ((wp->upfd = open(wp->uploadTmp, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0600)) < 0) { websError(wp, HTTP_CODE_INTERNAL_SERVER_ERROR, "Can't open upload temp file %s", wp->uploadTmp); return -1; } /* Create the files[id] */ file = wp->currentFile = walloc(sizeof(WebsUpload)); memset(file, 0, sizeof(WebsUpload)); file->clientFilename = sclone(wp->clientFilename); file->filename = sclone(wp->uploadTmp); } key = nextPair; } } else if (scaselesscmp(headerTok, "Content-Type") == 0) { if (wp->clientFilename) { trace(5, "Set files[%s][CONTENT_TYPE] = %s", wp->uploadVar, rest); wp->currentFile->contentType = sclone(rest); } } return 0; }
int ej_show_sysinfo(int eid, webs_t wp, int argc, char_t ** argv) { char *type; char result[2048]; int retval = 0; struct sysinfo sys; char *tmp; strcpy(result,"None"); if (ejArgs(argc, argv, "%s", &type) < 1) { websError(wp, 400, "Insufficient args\n"); return retval; } if (type) { if (strcmp(type,"cpu.model") == 0) { char *buffer = read_whole_file("/proc/cpuinfo"); if (buffer) { tmp = strstr(buffer, "system type"); if (tmp) sscanf(tmp, "system type : %[^\n]", result); free(buffer); } } else if(strcmp(type,"cpu.freq") == 0) { tmp = nvram_get("clkfreq"); if (tmp) sscanf(tmp,"%[^,]s", result); } else if(strcmp(type,"memory.total") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.totalram/(float)MBYTES)); } else if(strcmp(type,"memory.free") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.freeram/(float)MBYTES)); } else if(strcmp(type,"memory.buffer") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.bufferram/(float)MBYTES)); } else if(strcmp(type,"memory.swap.total") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.totalswap/(float)MBYTES)); } else if(strcmp(type,"memory.swap.used") == 0) { sysinfo(&sys); sprintf(result,"%.2f",((sys.totalswap - sys.freeswap) / (float)MBYTES)); } else if(strcmp(type,"cpu.load.1") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.loads[0] / (float)(1<<SI_LOAD_SHIFT))); } else if(strcmp(type,"cpu.load.5") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.loads[1] / (float)(1<<SI_LOAD_SHIFT))); } else if(strcmp(type,"cpu.load.15") == 0) { sysinfo(&sys); sprintf(result,"%.2f",(sys.loads[2] / (float)(1<<SI_LOAD_SHIFT))); } else if(strcmp(type,"nvram.total") == 0) { sprintf(result,"%d",NVRAM_SPACE); } else if(strcmp(type,"nvram.used") == 0) { char *buf; int size = 0; buf = malloc(NVRAM_SPACE); if (buf) { nvram_getall(buf, NVRAM_SPACE); tmp = buf; while (*tmp) tmp += strlen(tmp) +1; size = sizeof(struct nvram_header) + (int) tmp - (int) buf; free(buf); } sprintf(result,"%d",size); } else if(strcmp(type,"jffs.usage") == 0) { struct statvfs fiData; char *mount_info = read_whole_file("/proc/mounts"); if ((mount_info) && (strstr(mount_info, "/jffs")) && (statvfs("/jffs",&fiData) == 0 )) { sprintf(result,"%.2f / %.2f MB",((fiData.f_blocks-fiData.f_bfree) * fiData.f_frsize / (float)MBYTES) ,(fiData.f_blocks * fiData.f_frsize / (float)MBYTES)); } else { strcpy(result,"<i>Unmounted</i>"); } if (mount_info) free(mount_info); } else if(strncmp(type,"temperature",11) == 0) { unsigned int temperature; int radio=0; sscanf(type,"temperature.%d", &radio); temperature = get_phy_temperature(radio); if (temperature == 0) strcpy(result,"<i>disabled</i>"); else sprintf(result,"%u°C", temperature); } else if(strcmp(type,"conn.total") == 0) { FILE* fp; fp = fopen ("/proc/sys/net/ipv4/netfilter/ip_conntrack_count", "r"); if (fp) { if (fgets(result, sizeof(result), fp) != NULL) { fclose(fp); } } } else if(strcmp(type,"conn.active") == 0) { char buf[256]; FILE* fp; unsigned int established = 0; fp = fopen("/proc/net/nf_conntrack", "r"); if (fp) { while (fgets(buf, sizeof(buf), fp) != NULL) { if (strstr(buf,"ESTABLISHED") || ((strstr(buf,"udp")) && (strstr(buf,"ASSURED")))) established++; } fclose(fp); } sprintf(result,"%u",established); } else if(strcmp(type,"conn.max") == 0) { FILE* fp; fp = fopen ("/proc/sys/net/ipv4/netfilter/ip_conntrack_max", "r"); if (fp) { if (fgets(result, sizeof(result), fp) != NULL) { fclose(fp); } } } else if(strncmp(type,"conn.wifi",9) == 0) { int count, radio; char command[10]; sscanf(type,"conn.wifi.%d.%9s", &radio, command); if (strcmp(command,"autho") == 0) { count = get_wifi_clients(radio,SI_WL_QUERY_AUTHO); } else if (strcmp(command,"authe") == 0) { count = get_wifi_clients(radio,SI_WL_QUERY_AUTHE); } else if (strcmp(command,"assoc") == 0) { count = get_wifi_clients(radio,SI_WL_QUERY_ASSOC); } else { count = 0; } if (count == -1) strcpy(result,"<i>off</i>"); else sprintf(result,"%d",count); } else if(strcmp(type,"driver_version") == 0 ) { system("/usr/sbin/wl ver >/tmp/output.txt"); char *buffer = read_whole_file("/tmp/output.txt"); if (buffer) { if (tmp = strstr(buffer, "\n")) strncpy(result, tmp+1, sizeof result); else strncpy(result, buffer, sizeof result); free(buffer); unlink("/tmp/output.txt"); } } else if(strncmp(type,"pid",3) ==0 ) { char service[32]; sscanf(type, "pid.%31s", service); if (strlen(service)) sprintf(result, "%d", pidof(service)); } else if(strncmp(type,"vpnstatus",9) == 0 ) { int num = 0; char service[10], buf[256]; sscanf(type,"vpnstatus.%9[^.].%d", service, &num); if ( strlen(service) && (num > 0) ) { // Trigger OpenVPN to update the status file snprintf(buf, sizeof(buf), "vpn%s%d", service, num); killall(buf, SIGUSR2); // Give it a chance to update the file sleep(1); // Read the status file and repeat it verbatim to the caller sprintf(buf,"/etc/openvpn/%s%d/status", service, num); char *buffer = read_whole_file(buf); if (buffer) { strncpy(result, buffer, sizeof(result)); free(buffer); } } } else { strcpy(result,"Not implemented"); } } retval += websWrite(wp, result); return retval; }
int websAspRequest(webs_t wp, char_t *lpath) { websStatType sbuf; char *rbuf; char_t *token, *lang, *result, *path, *ep, *cp, *buf, *nextp; char_t *last; int rc, engine, len, ejid; a_assert(websValid(wp)); a_assert(lpath && *lpath); rc = -1; buf = NULL; rbuf = NULL; engine = EMF_SCRIPT_EJSCRIPT; wp->flags |= WEBS_HEADER_DONE; path = websGetRequestPath(wp); /* * Create Ejscript instance in case it is needed */ ejid = ejOpenEngine(wp->cgiVars, websAspFunctions); if (ejid < 0) { websError(wp, 200, T("Can't create Ejscript engine")); goto done; } ejSetUserHandle(ejid, (int) wp); if (websPageStat(wp, lpath, path, &sbuf) < 0) { websError(wp, 200, T("Can't stat %s"), lpath); goto done; } /* * Create a buffer to hold the ASP file in-memory */ len = sbuf.size * sizeof(char); if ((rbuf = balloc(B_L, len + 1)) == NULL) { websError(wp, 200, T("Can't get memory")); goto done; } rbuf[len] = '\0'; if (websPageReadData(wp, rbuf, len) != len) { websError(wp, 200, T("Cant read %s"), lpath); goto done; } websPageClose(wp); /* * Convert to UNICODE if necessary. */ if ((buf = ballocAscToUni(rbuf, len)) == NULL) { websError(wp, 200, T("Can't get memory")); goto done; } /* * Scan for the next "<%" */ last = buf; rc = 0; while (rc == 0 && *last && ((nextp = gstrstr(last, T("<%"))) != NULL)) { websWriteBlock(wp, last, (nextp - last)); nextp = skipWhite(nextp + 2); /* * Decode the language */ token = T("language"); if ((lang = strtokcmp(nextp, token)) != NULL) { if ((cp = strtokcmp(lang, T("=javascript"))) != NULL) { engine = EMF_SCRIPT_EJSCRIPT; } else { cp = nextp; } nextp = cp; } /* * Find tailing bracket and then evaluate the script */ if ((ep = gstrstr(nextp, T("%>"))) != NULL) { *ep = '\0'; last = ep + 2; nextp = skipWhite(nextp); /* * Handle backquoted newlines */ for (cp = nextp; *cp; ) { if (*cp == '\\' && (cp[1] == '\r' || cp[1] == '\n')) { *cp++ = ' '; while (*cp == '\r' || *cp == '\n') { *cp++ = ' '; } } else { cp++; } } /* * Now call the relevant script engine. Output is done directly * by the ASP script procedure by calling websWrite() */ if (*nextp) { result = NULL; if (engine == EMF_SCRIPT_EJSCRIPT) { rc = scriptEval(engine, nextp, &result, ejid); } else { rc = scriptEval(engine, nextp, &result, (int) wp); } if (rc < 0) { /* * On an error, discard all output accumulated so far * and store the error in the result buffer. Be careful if the * user has called websError() already. */ if (websValid(wp)) { if (result) { websWrite(wp, T("<h2><b>ASP Error: %s</b></h2>\n"), result); websWrite(wp, T("<pre>%s</pre>"), nextp); bfree(B_L, result); } else { websWrite(wp, T("<h2><b>ASP Error</b></h2>\n%s\n"), nextp); } websWrite(wp, T("</body></html>\n")); rc = 0; } goto done; } } } else { websError(wp, 200, T("Unterminated script in %s: \n"), lpath); rc = -1; goto done; } } /* * Output any trailing HTML page text */ if (last && *last && rc == 0) { websWriteBlock(wp, last, gstrlen(last)); } rc = 0; /* * Common exit and cleanup */ done: if (websValid(wp)) { websPageClose(wp); if (ejid >= 0) { ejCloseEngine(ejid); } } bfreeSafe(B_L, buf); bfreeSafe(B_L, rbuf); return rc; }
/* * Process a form request. Returns 1 always to indicate it handled the URL */ int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t* query) { cgiRec *cgip; sym_t *s; char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE]; char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep; int n, envpsize, argpsize, pHandle, cid; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path && *path == '/'); websStats.cgiHits++; /* * Extract the form name and then build the full path name. The form * name will follow the first '/' in path. */ gstrncpy(cgiBuf, path, TSZ(cgiBuf)); if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) { websError(wp, 200, T("Missing CGI name")); return 1; } cgiName++; if ((cp = gstrchr(cgiName, '/')) != NULL) { *cp = '\0'; } fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(), CGI_BIN, cgiName); #ifndef VXWORKS /* * See if the file exists and is executable. If not error out. * Don't do this step for VxWorks, since the module may already * be part of the OS image, rather than in the file system. */ { gstat_t sbuf; if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) { websError(wp, 200, T("CGI process file does not exist")); bfree(B_L, cgiPath); return 1; } #if (defined (WIN) || defined (CE)) if (gstrstr(cgiPath, T(".exe")) == NULL && gstrstr(cgiPath, T(".bat")) == NULL) { #elif (defined (NW)) if (gstrstr(cgiPath, T(".nlm")) == NULL) { #else if (gaccess(cgiPath, X_OK) != 0) { #endif /* WIN || CE */ websError(wp, 200, T("CGI process file is not executable")); bfree(B_L, cgiPath); return 1; } } #endif /* ! VXWORKS */ /* * Get the CWD for resetting after launching the child process CGI */ ggetcwd(cwd, FNAMESIZE); /* * Retrieve the directory of the child process CGI */ if ((cp = gstrrchr(cgiPath, '/')) != NULL) { *cp = '\0'; gchdir(cgiPath); *cp = '/'; } /* * Build command line arguments. Only used if there is no non-encoded * = character. This is indicative of a ISINDEX query. POST separators * are & and others are +. argp will point to a balloc'd array of * pointers. Each pointer will point to substring within the * query string. This array of string pointers is how the spawn or * exec routines expect command line arguments to be passed. Since * we don't know ahead of time how many individual items there are in * the query string, the for loop includes logic to grow the array * size via brealloc. */ argpsize = 10; argp = balloc(B_L, argpsize * sizeof(char_t *)); *argp = cgiPath; n = 1; if (gstrchr(query, '=') == NULL) { websDecodeUrl(query, query, gstrlen(query)); for (cp = gstrtok(query, T(" ")); cp != NULL; ) { *(argp+n) = cp; n++; if (n >= argpsize) { argpsize *= 2; argp = brealloc(B_L, argp, argpsize * sizeof(char_t *)); } cp = gstrtok(NULL, T(" ")); } } *(argp+n) = NULL; /* * Add all CGI variables to the environment strings to be passed * to the spawned CGI process. This includes a few we don't * already have in the symbol table, plus all those that are in * the cgiVars symbol table. envp will point to a balloc'd array of * pointers. Each pointer will point to a balloc'd string containing * the keyword value pair in the form keyword=value. Since we don't * know ahead of time how many environment strings there will be the * for loop includes logic to grow the array size via brealloc. */ envpsize = WEBS_SYM_INIT; envp = balloc(B_L, envpsize * sizeof(char_t *)); n = 0; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"), CGI_BIN, cgiName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType); n++; for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) { if (s->content.valid && s->content.type == string && gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 && gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) { fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string, s->content.value.string); n++; if (n >= envpsize) { envpsize *= 2; envp = brealloc(B_L, envp, envpsize * sizeof(char_t *)); } } } if (wp->flags & WEBS_CGI_UPLOAD){ // set filename into enviornment variables fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), T("UPLOAD_FILENAME"), wp->cgiStdin); n++; } *(envp+n) = NULL; /* * Create temporary file name(s) for the child's stdin and stdout. * For POST data the stdin temp file (and name) should already exist. */ if (wp->cgiStdin == NULL) { wp->cgiStdin = websGetCgiCommName(wp); } stdIn = wp->cgiStdin; stdOut = websGetCgiCommName(wp); /* * Now launch the process. If not successful, do the cleanup of resources. * If successful, the cleanup will be done after the process completes. */ if ((pHandle = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut)) == -1) { websError(wp, 200, T("failed to spawn CGI task")); for (ep = envp; *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgiPath); bfreeSafe(B_L, argp); bfreeSafe(B_L, envp); bfreeSafe(B_L, stdOut); } else { /* * If the spawn was successful, put this wp on a queue to be * checked for completion. */ cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec)); cgip = cgiList[cid]; cgip->handle = pHandle; cgip->stdIn = stdIn; cgip->stdOut = stdOut; cgip->cgiPath = cgiPath; cgip->argp = argp; cgip->envp = envp; cgip->wp = wp; cgip->fplacemark = 0; websTimeoutCancel(wp); } /* * Restore the current working directory after spawning child CGI */ gchdir(cwd); return 1; } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has */ void websCgiGatherOutput (cgiRec *cgip) { gstat_t sbuf; char_t cgiBuf[FNAMESIZE]; if ((gstat(cgip->stdOut, &sbuf) == 0) && (sbuf.st_size > cgip->fplacemark)) { int fdout; fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 ); /* * Check to see if any data is available in the * output file and send its contents to the socket. */ if (fdout >= 0) { webs_t wp = cgip->wp; int nRead; /* * Write the HTTP header on our first pass */ if (cgip->fplacemark == 0) { websWrite(wp, T("HTTP/1.0 200 OK\r\n")); } glseek(fdout, cgip->fplacemark, SEEK_SET); while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) { websWriteBlock(wp, cgiBuf, nRead); cgip->fplacemark += nRead; } gclose(fdout); } } } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has * completed, and if so, process its output and clean up. */ void websCgiCleanup() { cgiRec *cgip; webs_t wp; char_t **ep; int cid, nTries; for (cid = 0; cid < cgiMax; cid++) { if ((cgip = cgiList[cid]) != NULL) { int exit_status; wp = cgip->wp; websCgiGatherOutput (cgip); if ( websCheckCgiProc(cgip->handle, &exit_status) == 0) { /* * We get here if the CGI process has terminated. Clean up. */ nTries = 0; /* * Make sure we didn't miss something during a task switch. * Maximum wait is 100 times 10 msecs (1 second). */ while ((cgip->fplacemark == 0) && (nTries < 100)) { websCgiGatherOutput(cgip); /* * There are some cases when we detect app exit * before the file is ready. */ if (cgip->fplacemark == 0) { #ifdef WIN Sleep(10); #endif /* WIN*/ } nTries++; } if (cgip->fplacemark == 0) { websError(wp, 200, T("CGI generated no output")); } else { websDone(wp, 200); } /* * Remove the temporary re-direction files */ gunlink(cgip->stdIn); gunlink(cgip->stdOut); /* * Free all the memory buffers pointed to by cgip. * The stdin file name (wp->cgiStdin) gets freed as * part of websFree(). */ cgiMax = hFree((void***) &cgiList, cid); for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgip->cgiPath); bfreeSafe(B_L, cgip->argp); bfreeSafe(B_L, cgip->envp); bfreeSafe(B_L, cgip->stdOut); bfreeSafe(B_L, cgip); #if 0 //DAVIDM - we do not want this, netflash does it for us if(wp->has_firmware_upload_clean){ if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) != 0) return; sync(); doSystem("sleep 3 && reboot &"); } #endif } } } }
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) { websStatType sbuf; char_t *lpath, *tmp, *date; int bytes, flags, nchars, rc; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path); a_assert(query); flags = websGetRequestFlags(wp); /* * We do whitelist validation in addition to standard URL validation. * The whitelist should really catch anything invalid first. * If the whitelist check fails, rebuild the list and try again. * Also validate if we are not on a secure connection, but the whitelist * entry has the SSL flag set, do not serve the page. */ #ifdef WEBS_WHITELIST_SUPPORT printf ("wp->url: (%s)\n", wp->url); if ((rc = websWhitelistCheck(wp->url)) < 0) { websBuildWhitelist(); if ((rc = websWhitelistCheck(wp->url)) < 0) { websError(wp, 404, T("Cannot open URL: type 1")); return 1; } } if (!(flags & WEBS_SECURE) && (rc & WHITELIST_SSL)) { websError(wp, 500, T("HTTPS access required")); return 1; } #endif /* WEBS_WHITELIST_SUPPORT */ /* * Validate the URL and ensure that ".."s don't give access to unwanted files */ if (websValidateUrl(wp, path) < 0) { /* * preventing a cross-site scripting exploit -- you may restore the * following line of code to revert to the original behavior... websError(wp, 500, T("Invalid URL %s"), url); */ websError(wp, 500, T("Invalid URL")); websBuildWhitelist(); return 1; } lpath = websGetRequestLpath(wp); nchars = gstrlen(lpath) - 1; if (lpath[nchars] == '/' || lpath[nchars] == '\\') { lpath[nchars] = '\0'; } /* * If the file is a directory, redirect using the nominated default page */ if (websPageIsDirectory(lpath)) { nchars = gstrlen(path); if (path[nchars-1] == '/' || path[nchars-1] == '\\') { path[--nchars] = '\0'; } nchars += gstrlen(websDefaultPage) + 2; fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage); printf ("websDefaultHandler: tmp(%s)\n", tmp); websRedirect(wp, tmp); bfreeSafe(B_L, tmp); return 1; } printf ("we now open the web pages\n"); printf ("lpath(%s), path(%s)\n", lpath, path); /* * Open the document. Stat for later use. */ if (websPageOpen(wp, lpath, path, O_RDONLY | O_BINARY, 0666) < 0) { /* 10 Dec 02 BgP -- according to * <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>, * the proper code to return here is NOT 400 (old code), which is used * to indicate a malformed request. Here, the request is good, but the * error we need to tell the client about is 404 (Not Found). */ /* * 17 Mar 03 BgP -- prevent a cross-site scripting exploit websError(wp, 404, T("Cannot open URL %s"), url); */ websError(wp, 404, T("Cannot open URL, type 2")); websBuildWhitelist(); return 1; } printf ("lpath(%s), path(%s)\n", lpath, path); if (websPageStat(wp, lpath, path, &sbuf) < 0) { /* * 17 Mar 03 BgP * prevent a cross-site scripting exploit websError(wp, 400, T("Cannot stat page for URL %s"), url); */ websError(wp, 400, T("Cannot stat page for URL")); websBuildWhitelist(); return 1; } /* * If the page has not been modified since the user last received it and it * is not dynamically generated each time (ASP), then optimize request by * sending a 304 Use local copy response */ websStats.localHits++; #ifdef WEBS_IF_MODIFIED_SUPPORT if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) { if (sbuf.mtime <= wp->since) { websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n")); /* * by license terms the following line of code must * not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); if (flags & WEBS_KEEP_ALIVE) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE); websDone(wp, 304); return 1; } } #endif /* * Output the normal HTTP response header */ if ((date = websGetDateString(NULL)) != NULL) { websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date); /* * The Server HTTP header below must not be modified unless * explicitly allowed by licensing terms. */ #ifdef WEBS_SSL_SUPPORT websWrite(wp, T("Server: %s/%s %s/%s\r\n"), WEBS_NAME, WEBS_VERSION, SSL_NAME, SSL_VERSION); #else websWrite(wp, T("Server: %s/%s\r\n"), WEBS_NAME, WEBS_VERSION); #endif bfree(B_L, date); } flags |= WEBS_HEADER_DONE; /* * If this is an ASP request, ensure the remote browser doesn't cache it. * Send back both HTTP/1.0 and HTTP/1.1 cache control directives */ if (flags & WEBS_ASP) { bytes = 0; websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n")); } else { if ((date = websGetDateString(&sbuf)) != NULL) { websWrite(wp, T("Last-modified: %s\r\n"), date); bfree(B_L, date); } bytes = sbuf.size; } if (bytes) { websWrite(wp, T("Content-length: %d\r\n"), bytes); websSetRequestBytes(wp, bytes); } websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp)); if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); /* * All done if the browser did a HEAD request */ if (flags & WEBS_HEAD_REQUEST) { websDone(wp, 200); return 1; } /* * Evaluate ASP requests */ if (flags & WEBS_ASP) { if (websAspRequest(wp, lpath) < 0) { return 1; } websDone(wp, 200); return 1; } /* * Return the data via background write */ websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); return 1; }