static int websTidyUrl(webs_t wp) { char_t *parts[64]; /* Array of ptr's to URL parts */ char_t *token, *url, *tidyurl; int i, len, npart; a_assert(websValid(wp)); /* * Copy the string so we don't destroy the original (yet) */ url = bstrdup(B_L, wp->url); websDecodeUrl(url, url, gstrlen(url)); len = npart = 0; parts[0] = NULL; token = gstrtok(url, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } /* * Re-construct URL. Need extra space all "/" and null. */ if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) { tidyurl = balloc(B_L, (len + 2) * sizeof(char_t)); *tidyurl = '\0'; for (i = 0; i < npart; i++) { gstrcat(tidyurl, T("/")); gstrcat(tidyurl, parts[i]); } bfree(B_L, url); bfree(B_L, wp->url); wp->url = tidyurl; return 0; } else { bfree(B_L, url); return -1; } }
char_t *websCalcUrlDigest(webs_t wp) { char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method; a_assert(wp); digest = NULL; /* * Calculate first portion of digest H(A1) */ a1 = NULL; fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password); a_assert(a1); a1prime = websMD5(a1); bfreeSafe(B_L, a1); /* * Calculate second portion of digest H(A2) */ method = websGetVar(wp, T("REQUEST_METHOD"), NULL); a_assert(method); /* Fixes by Richard Laing, 2003/7/15 */ a2 = balloc(B_L, (gstrlen(method) +2 + gstrlen(wp->url) ) * sizeof(char_t)); a_assert(a2); gsprintf(a2, T("%s:%s"), method, wp->url); a2prime = websMD5(a2); bfreeSafe(B_L, a2); /* * Construct final digest KD(H(A1):nonce:H(A2)) */ a_assert(a1prime); a_assert(a2prime); a_assert(wp->nonce); preDigest = NULL; if (!wp->qop) { fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime); } else { fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"), a1prime, wp->nonce, wp->nc, wp->cnonce, wp->qop, a2prime); } a_assert(preDigest); digest = websMD5(preDigest); /* * Now clean up */ bfreeSafe(B_L, a1prime); bfreeSafe(B_L, a2prime); bfreeSafe(B_L, preDigest); return digest; }
/** * @function GUI_W_UsrEntryAdd * @brief add user entry * @param const rect_st *rec: object dimension * @param const void *buffer: text of the user entry (may be modified) * @param uint16_t sizeMax: size (in bytes) of the buffer, including the \0 * @return g_obj_st *: pointer to the associated generic object if succedeed, NULL if error. */ g_obj_st /*@null@*/ *GUI_W_UsrEntryAdd(const rect_st *rec, void *buffer, uint16_t sizeMax, bool bEditable) { g_obj_st *g_obj = NULL, *res = NULL; usr_entry_st *entry = NULL; /*check parameters*/ if(rec != NULL && buffer != NULL && sizeMax > 2) { /*allocate a generic object*/ g_obj = GUI_AddGenericObject(); if(g_obj != NULL) { /*allocate a entry*/ entry = salloc(sizeof(usr_entry_st)); if(entry != NULL) { /*entry settings*/ entry->buffer = (uint8_t *) buffer; entry->buffer[sizeMax - 1] = 0; /*ensure that the user string is \0 terminated*/ entry->sizeMax = sizeMax; entry->len = gstrlen(entry->buffer); entry->tBlink = 0; entry->tScroll = 0; entry->bBlink = false; entry->bPressed = false; entry->bEditable = bEditable; entry->colText = GetColor(G_COL_TEXT); entry->font = GetCurrentFont(); /*start displaying at the very begining of the string*/ entry->offsetDisplay = 0; /*start with the whole string selected*/ entry->cursStart = 0; entry->cursStop = gstrlen(entry->buffer); /*linkage between generic obj & usr entry*/ g_obj->rec = *rec; g_obj->draw = EntryDraw; g_obj->task = EntryTask; g_obj->obj = entry; res = g_obj; } } } return res; }
char_t *websMD5(char_t *string) { char_t *strReturn; a_assert(string && *string); if (string && *string) { char *strTemp, *strHash; int nLen; /* * Convert input char_t string to char string */ nLen = gstrlen(string); strTemp = ballocUniToAsc(string, nLen + 1); /* * Execute the digest calculation */ strHash = websMD5binary((unsigned char *)strTemp, nLen); /* * Convert the returned char string digest to a char_t string */ nLen = strlen(strHash); strReturn = ballocAscToUni(strHash, nLen); /* * Free up the temporary allocated resources */ bfree(B_L, strTemp); bfree(B_L, strHash); } else { strReturn = NULL; } return strReturn; }
//---------------------------------------------------------------------------- // concatenate src to dst, always zero terminate //---------------------------------------------------------------------------- tChar* xstrcatn(tChar* pDst, size_t cbDst, tCChar* pSrc, tUint32* pdwError) { register tChar *pdst = pDst; register const tChar *psrc = pSrc; register size_t cbdst = cbDst; size_t cb = gstrlen(pDst); // clear error if (pdwError) *pdwError = XERROR_SUCCESS; do { // dst already overflowed if (cb >= cbdst) break; // append src, leave room for terminating zero for (cbdst -= cb, pdst += cb; *psrc && (cbdst > 1); *pdst++ = *psrc++, cbdst--); // zero terminate *pdst = '\0'; } while (FALSE); // report error if (*psrc && pdwError) *pdwError = XERROR_RESOURCES; return pDst; } // xstrcatn
static int dbWriteKeyValue(int fd, char_t *key, char_t *value) { int rc; int len; char_t *pLineOut; a_assert(key && *key); a_assert(value); fmtAlloc(&pLineOut, BUF_MAX, T("%s=%s\n"), key, value); if (pLineOut) { len = gstrlen(pLineOut); #ifdef CE rc = writeUniToAsc(fd, pLineOut, len); #else rc = gwrite(fd, pLineOut, len); #endif bfree(B_L, pLineOut); } else { rc = -1; } return rc; }
/** * @function StrInsert * @brief insert a string in another one * @param uint8_t *strDest: string destination * @param uint16_t strDestSize: size (in byte) of the string destination * @param const uint8_t *strIns: string to insert * @param uint16_t insPos: position in 'string destination' where to insert the strIns * @return uint16_t: return the new value of the insertion position */ static uint16_t StrInsert(uint8_t *strDest, uint16_t strDestSize, const uint8_t *strIns, uint16_t insPos) { int32_t pos; int32_t shiftCnt = gstrlen(strIns); /*shift the right part of the string*/ for(pos = strDestSize - 1; pos - shiftCnt >= insPos; pos--) { strDest[pos] = strDest[pos - shiftCnt]; } /*then copy the new content*/ while(insPos < strDestSize && *strIns != 0) { strDest[insPos] = *strIns; strIns++; insPos++; } /*always be sure that str is '\0' terminated*/ strDest[strDestSize - 1] = 0; /*always be sure that the insertion line is bounded into the string size*/ if(insPos > strDestSize - 1) insPos = strDestSize - 1; return insPos; }
/** * @function GUI_W_UsrEntryDelete * @brief Delete the selected string part (if any), or the car corresponding to insert line position * @param void *_g_obj: generic object * @return none */ void GUI_W_UsrEntryDelete(g_obj_st *obj) { uint16_t from, to; usr_entry_st *entry; if(obj != NULL && obj->draw == EntryDraw) { entry = (usr_entry_st *) obj->obj; if(entry->bEditable) { from = _MIN(entry->cursStart, entry->cursStop); to = _MAX(entry->cursStart, entry->cursStop); /*delecte the selection, or car located before the insert line*/ StrDelete(entry->buffer, entry->sizeMax, from, to); /*if there was no user selection, decrease the position of the insert bar*/ if(from == to && from > 0) { entry->cursStart--; entry->cursStop--; } /*always ensure that the resulting insert line is bounded into the string size*/ entry->len = gstrlen(entry->buffer); if(entry->len < entry->cursStart) entry->cursStart = entry->len; /*after a deletion, set insert line to the lower cursor; since insert line -> entry->cursStop = entry->cursStart*/ entry->cursStart = _MIN(entry->cursStart, entry->cursStop); entry->cursStop = entry->cursStart; /*force refresh*/ GUI_ObjSetNeedRefresh(obj, true); } } }
static int badPath(char_t* path, char_t* badPath, int badLen) { int retval = 0; int len = gstrlen(path); int i = 0; if (len <= badLen +1) { for (i = 0; i < badLen; ++i) { if (badPath[i] != gtolower(path[i])) { return 0; } } /* if we get here, the first 'badLen' characters match. * If 'path' is 1 character larger than 'badPath' and that extra * character is NOT a letter or a number, we have a bad path. */ retval = 1; if (badLen + 1 == len) { /* e.g. path == "aux:" */ if (gisalnum(path[len-1])) { /* the last character is alphanumeric, so we let this path go * through. */ retval = 0; } } } return retval; }
static char_t *strtokcmp(char_t *s1, char_t *s2) { int len; s1 = skipWhite(s1); len = gstrlen(s2); for (len = gstrlen(s2); len > 0 && (tolower(*s1) == tolower(*s2)); len--) { if (*s2 == '\0') { return s1; } s1++; s2++; } if (len == 0) { return s1; } return NULL; }
char_t *umGetAccessLimit(char_t *url) { char_t *urlRet, *urlCheck, *lastChar; int len; a_assert(url && *url); urlRet = NULL; urlCheck = bstrdup(B_L, url); a_assert(urlCheck); len = gstrlen(urlCheck); /* * Scan back through URL to see if there is a "parent" access limit */ while (len && !urlRet) { if (umAccessLimitExists(urlCheck)) { urlRet = bstrdup(B_L, urlCheck); } else { /* * Trim the end portion of the URL to the previous directory marker */ lastChar = urlCheck + len; lastChar--; while ((lastChar >= urlCheck) && ((*lastChar == '/') || (*lastChar == '\\'))) { *lastChar = 0; lastChar--; } while ((lastChar >= urlCheck) && (*lastChar != '/') && (*lastChar != '\\')) { *lastChar = 0; lastChar--; } len = gstrlen(urlCheck); } } bfree (B_L, urlCheck); return urlRet; }
void defaultTraceHandler(int level, char_t *buf) { /* * The following code would write all trace regardless of level * to stdout. */ if (buf) { if (0 == level) write(1, buf, gstrlen(buf)); } }
int ringqPutStr(ringq_t *rq, char_t *str) { int rc; a_assert(rq); a_assert(str); a_assert(rq->buflen == (rq->endbuf - rq->buf)); rc = ringqPutBlk(rq, (unsigned char*) str, gstrlen(str) * sizeof(char_t)); *((char_t*) rq->endp) = (char_t) '\0'; return rc; }
//---------------------------------------------------------------------------- // //---------------------------------------------------------------------------- void ICACHE_FLASH_ATTR mqttPublish(tCChar* szPfx, tCChar* szTopic, tCChar* szMsg) { if (!g_pMqtt) return; Debug.logTxt(CLSLVL_MQTT | 0x0000, "mqttPublish,topic=%s/%s/%s,msg=%s", AppSettings.mqttClientId.c_str(), szPfx, szTopic, szMsg); Debug.logBin(CLSLVL_MQTT | 0x0010, 2, szTopic, gstrlen(szTopic), "mqttPublish,topic=%s/%s/%s,msg=%s", AppSettings.mqttClientId.c_str(), szPfx, szTopic, szMsg); g_pMqtt->publish(AppSettings.mqttClientId + String("/") + String(szPfx) + String("/") + String(szTopic), String(szMsg)); g_mqttPktTx++; } // mqttPublishMessage
//---------------------------------------------------------------------------- // duplicate string //---------------------------------------------------------------------------- tChar* xstrdup(tCChar* pStr) { tChar *pstr; tInt32 nLen; if (pStr == NULL) pStr = ""; nLen = gstrlen(pStr) + 1; if ((pstr = (tChar*) malloc(nLen))) gstrcpy(pstr, pStr); return pstr; } // xstrdup
char_t *bstrdup(B_ARGS_DEC, char_t *s) { char_t *cp; int len; if (s == NULL) { s = T(""); } len = gstrlen(s) + 1; if ((cp = balloc(B_ARGS, len * sizeof(char_t))) != NULL) { gstrcpy(cp, s); } return cp; }
int websLaunchCgiProc(char_t *cgiPath, char_t **argp, char_t **envp, char_t *stdIn, char_t *stdOut) { PROCESS_INFORMATION procinfo; /* Information about created proc */ DWORD dwCreateFlags; char *fulldir; BOOL bReturn; int i, nLen; /* * Replace directory delimiters with Windows-friendly delimiters */ nLen = gstrlen(cgiPath); for (i = 0; i < nLen; i++) { if (cgiPath[i] == '/') { cgiPath[i] = '\\'; } } fulldir = NULL; dwCreateFlags = CREATE_NEW_CONSOLE; /* * CreateProcess returns errors sometimes, even when the process was * started correctly. The cause is not evident. For now: we detect * an error by checking the value of procinfo.hProcess after the call. */ procinfo.hThread = NULL; bReturn = CreateProcess( cgiPath, /* Name of executable module */ NULL, /* Command line string */ NULL, /* Process security attributes */ NULL, /* Thread security attributes */ 0, /* Handle inheritance flag */ dwCreateFlags, /* Creation flags */ NULL, /* New environment block */ NULL, /* Current directory name */ NULL, /* STARTUPINFO */ &procinfo); /* PROCESS_INFORMATION */ if (bReturn == 0) { DWORD dw; dw = GetLastError(); return -1; } else { CloseHandle(procinfo.hThread); } return (int) procinfo.dwProcessId; }
int socketWriteString(int sid, char_t *buf) { #ifdef UNICODE char *byteBuf; int r, len; len = gstrlen(buf); byteBuf = ballocUniToAsc(buf, len); r = socketWrite(sid, byteBuf, len); bfreeSafe(B_L, byteBuf); return r; #else return socketWrite(sid, buf, strlen(buf)); #endif /* UNICODE */ }
/** * @function GUI_W_UsrEntrySelectAll * @brief select the whole string of the entry key * @param void *_g_obj: generic object * @return none */ void GUI_W_UsrEntrySelectAll(g_obj_st *obj) { usr_entry_st *entry; if(obj != NULL && obj->draw == EntryDraw) { entry = (usr_entry_st *) obj->obj; /*update selection cursors*/ entry->cursStart = 0; entry->cursStop = gstrlen(entry->buffer); /*force refresh*/ GUI_ObjSetNeedRefresh(obj, true); } }
static int websPublishHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int sid, char_t *url, char_t *path, char_t *query) { int len; a_assert(websValid(wp)); a_assert(path); /* * Trim the urlPrefix off the path and set the webdirectory. Add one to step * over the trailing '/' */ len = gstrlen(urlPrefix) + 1; websSetRequestPath(wp, webDir, &path[len]); return 0; }
void basicSetProductDir(char_t *proddir) { int len; if (basicProdDir != NULL) { bfree(B_L, basicProdDir); } basicProdDir = bstrdup(B_L, proddir); /* * Make sure that prefix-directory doesn't end with a '/' */ len = gstrlen(basicProdDir); if ((len > 0) && *(basicProdDir + len - 1) == '/') { *(basicProdDir+len-1) = '\0'; } }
int websRomOpen() { websRomPageIndexType *wip; int nchars; char_t name[SYM_MAX]; romTab = symOpen(WEBS_SYM_INIT); for (wip = websRomPageIndex; wip->path; wip++) { gstrncpy(name, wip->path, SYM_MAX); nchars = gstrlen(name) - 1; if (nchars > 0 && (name[nchars] == '/' || name[nchars] == '\\')) { name[nchars] = '\0'; } symEnter(romTab, name, valueInteger((int) wip), 0); } return 0; }
int websAspWrite(int ejid, webs_t wp, int argc, char_t **argv) { int i; a_assert(websValid(wp)); for (i = 0; i < argc; ) { a_assert(argv); if (websWriteBlock(wp, argv[i], gstrlen(argv[i])) < 0) { return -1; } if (++i < argc) { if (websWriteBlock(wp, T(" "), 2) < 0) { return -1; } } } return 0; }
//---------------------------------------------------------------------------- // convert hex string to tUint8 array, return number of bytes in output, 0=error //---------------------------------------------------------------------------- tUint32 xstrHexToUint8(tUint8* pOut, tChar* pIn) { tUint32 cbRet = 0, dwLen, dw; do { // must be even length if ((dwLen = gstrlen(pIn)) % 2) break; for (dwLen /= 2; cbRet < dwLen; cbRet++) { if ((dw = _xstrHexOctet(&pIn)) < 256) *pOut++ = (tUint8) dw; else { cbRet = 0; break; } // else } // for } while (FALSE); return cbRet; } // xstrHexToUint8
int websUrlHandlerDefine(char_t *urlPrefix, char_t *webDir, int arg, int (*handler)(webs_t wp, char_t *urlPrefix, char_t *webdir, int arg, char_t *url, char_t *path, char_t *query), int flags) { websUrlHandlerType *sp; int len; a_assert(urlPrefix); a_assert(handler); /* * Grow the URL handler array to create a new slot */ len = (websUrlHandlerMax + 1) * sizeof(websUrlHandlerType); if ((websUrlHandler = brealloc(B_L, websUrlHandler, len)) == NULL) { return -1; } sp = &websUrlHandler[websUrlHandlerMax++]; memset(sp, 0, sizeof(websUrlHandlerType)); sp->urlPrefix = bstrdup(B_L, urlPrefix); sp->len = gstrlen(sp->urlPrefix); if (webDir) { sp->webDir = bstrdup(B_L, webDir); } else { sp->webDir = bstrdup(B_L, T("")); } sp->handler = handler; sp->arg = arg; sp->flags = flags; /* * Sort in decreasing URL length order observing the flags for first and last */ qsort(websUrlHandler, websUrlHandlerMax, sizeof(websUrlHandlerType), websUrlHandlerSort); return 0; }
/** * @function GUI_W_UsrEntryInsert * @brief insert a string into the string of the entry key, at current user insert position * @param void *_g_obj: generic object * @param const uint8_t *strIns: string to insert * @return none */ void GUI_W_UsrEntryInsert(g_obj_st *obj, const uint8_t *strIns) { usr_entry_st *entry; if(obj != NULL && obj->draw == EntryDraw && strIns != NULL) { entry = (usr_entry_st *) obj->obj; if(entry->bEditable) { /*if some text is selected, delete it first; after GUI_UsrEntryDelKey() execution, entry->cursStart == entry->cursStop*/ if(entry->cursStart != entry->cursStop) GUI_W_UsrEntryDelete(obj); /*insert string at insertion pos & update selection cursors*/ entry->cursStop = entry->cursStart = StrInsert(entry->buffer, entry->sizeMax, strIns, entry->cursStart); /*update str len*/ entry->len = gstrlen(entry->buffer); /*force refresh*/ GUI_ObjSetNeedRefresh(obj, true); } } }
/** * @function RotValDraw * @brief rotary value draw function * @param void *_g_obj: generic object * @param void *_obj: rot val object * @return none */ static void RotValDraw(void *_g_obj, void *_obj) { g_obj_st *g_obj; rot_val_st *rval; rect_st lrec, absRec; color_t colBack, colText, colSetText; uint8_t digitId, len, glyph, str[MAX_VAL_STR], typeBox = 0; bool bNeg; surfaceId_t idSurface = SURFACE_LCD; /*retrieve generic & specific object*/ if(_g_obj != NULL && _obj != NULL) { g_obj = (g_obj_st *) _g_obj; rval = (rot_val_st*) _obj; /*try to create a double buffer in RAM*/ absRec = g_obj->rec; absRec.x = 0; absRec.y = 0; idSurface = P2D_SurfaceCreate(&absRec); if(idSurface != SURFACE_LCD) { P2D_SetDest(idSurface); } else { absRec = g_obj->rec; } /*color selection*/ if(GUI_ObjIsDisabled(g_obj)) { SetLut(G_LUT_DISABLED); colBack = GetColor(G_COL_E_BACKGROUND); colText = GetColor(G_COL_D_TEXT); colSetText = GetColor(G_COL_D_TEXT); typeBox = 2; } else if(GUI_ObjIsPressed(g_obj)) { SetLut(G_LUT_NORMAL); colBack = GetColor(G_COL_E_BACKGROUND); colText = rval->colorText; colSetText = GetColor(G_COL_SPECIAL); } else { SetLut(G_LUT_NORMAL); colBack = GetColor(G_COL_E_BACKGROUND); colText = rval->colorText; if(rval->lock != 0) colSetText = rval->colorText; else colSetText = GetColor(G_COL_SPECIAL); } /*P2D configuration*/ P2D_SetDisplayMode(DISPLAY_SOLID); P2D_SetLineType(LINE_SOLID); SetFont(rval->font); /*background*/ P2D_SetColors(colBack, colBack); lrec = absRec; P2D_SetColors(COLOR_LIGHT_GREY, COLOR_LIGHT_GREY); DrawBox(&lrec, typeBox); /*sprite*/ P2D_SetDisplayMode(DISPLAY_TRANSPARENT); if(rval->img != 0) { Sprite(lrec.x + 4, lrec.y + ((int32_t)lrec.h - SpriteGetHeight(rval->img)) / 2, rval->img); } /*display the value's unit string*/ lrec.x += 1; lrec.y += 1; lrec.w -= 2; lrec.h -= 2; P2D_SetColors(colText, colBack); lrec.y = absRec.y + ((coord_t)absRec.h - P2D_GetTextHeight()) / 2; P2D_PutText(absRec.x + rval->xUnit, lrec.y, rval->strUnit); /*format value*/ (void) snprintf( (char *)str, MAX_VAL_STR, "%d", *(rval->pVar)); len = gstrlen(str); bNeg = *(rval->pVar) < 0 ? true : false; /*display each digit, one by one, from right to left*/ for(digitId = 0; IsValidDigit(rval, digitId) == true; digitId++) { /*get the x coord of the current digit*/ lrec.x = absRec.x + GetDigitCoord(rval, digitId); /*special color + highlighted if the current digit is the selected one*/ if(digitId == rval->selectedDigit && rval->lock == false) { P2D_SetColors(colSetText, colBack); } else { P2D_SetColors(colText, colBack); } /*display the snprintf content, excepting the '-'*/ if(digitId < len) { glyph = str[len - digitId - 1]; if(glyph == (uint8_t)'-') glyph = (uint8_t)'0'; /*will be displayed at end*/ } /*for small value (i.e. digitId >= strlen), fill with '0'*/ else { glyph = (uint8_t)'0'; } P2D_PutGlyph(lrec.x, lrec.y, glyph); } /*display the sign, only if negative*/ if(bNeg) { P2D_SetColors(colText, colBack); lrec.x = absRec.x + GetDigitCoord(rval, digitId); P2D_PutGlyph(lrec.x, lrec.y, (uint8_t)'-'); } /*display the dot, if any*/ if(rval->posDot > 0) { P2D_SetColor(colText); lrec.x = absRec.x + GetDigitCoord(rval, rval->posDot - 1) - rval->spacing; P2D_SetColors(colText, colBack); P2D_PutGlyph(lrec.x, lrec.y, (uint8_t) '.'); } /*if the double buffer was active, flip it to the screen*/ if(idSurface != SURFACE_LCD) { P2D_SetDest(SURFACE_LCD); P2D_CopySurface(idSurface, &absRec, &(g_obj->rec)); P2D_SurfaceDelete(idSurface); } } }
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 websValidateUrl(webs_t wp, char_t *path) { char_t *parts[64]; /* Array of ptr's to URL parts */ char_t *token, *dir, *lpath; int i, len, npart; a_assert(websValid(wp)); a_assert(path); dir = websGetRequestDir(wp); if (dir == NULL || *dir == '\0') { return -1; } /* * Copy the string so we don't destroy the original */ path = bstrdup(B_L, path); websDecodeUrl(path, path, gstrlen(path)); len = npart = 0; parts[0] = NULL; /* * 22 Jul 02 -- there were reports that a directory traversal exploit was * possible in the WebServer running under Windows if directory paths * outside the server's specified root web were given by URL-encoding the * backslash character, like: * * GoAhead is vulnerable to a directory traversal bug. A request such as * * GoAhead-server/../../../../../../../ results in an error message * 'Cannot open URL'. * However, by encoding the '/' character, it is possible to break out of * the * web root and read arbitrary files from the server. * Hence a request like: * * GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the * contents of the win.ini file. * (Note that the description uses forward slashes (0x2F), but the example * uses backslashes (0x5C). In my tests, forward slashes are correctly * trapped, but backslashes are not. The code below substitutes forward * slashes for backslashes before attempting to validate that there are no * unauthorized paths being accessed. */ token = gstrchr(path, '\\'); while (token != NULL) { *token = '/'; token = gstrchr(token, '\\'); } token = gstrtok(path, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } /* * Create local path for document. Need extra space all "/" and null. */ if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) { lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t)); gstrcpy(lpath, dir); for (i = 0; i < npart; i++) { gstrcat(lpath, T("/")); gstrcat(lpath, parts[i]); } websSetRequestLpath(wp, lpath); bfree(B_L, path); bfree(B_L, lpath); } else { bfree(B_L, path); return -1; } return 0; }
void defaultErrorHandler(int etype, char_t *msg) { write(1, msg, gstrlen(msg)); }