//Sends Content-encoding header if the requested file was GZIP compressed //If the client does not sent the Accept-encoding, send out a static html message. const char* sendGZIPEncodingIfNeeded(HttpdConnData *connData) { int i=0; char acceptEncodingBuffer[64]; //Go find the extension char *ext=connData->url+(strlen(connData->url)-1); while (ext!=connData->url && *ext!='.') ext--; if (*ext=='.') ext++; //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... while (gzippedFileTypes[i]!=NULL) { if (os_strcmp(ext, gzippedFileTypes[i])==0) { //when serving gzipped files check the browser's "Accept-Encoding" header //if the client does not advertises that he accepts GZIP send a warning message (telnet users for e.g.) httpdGetHeader(connData, "Accept-Encoding", acceptEncodingBuffer, 64); if (os_strstr(acceptEncodingBuffer, "gzip") == NULL) { //No Accept-Encoding: gzip header present return gzipNonSupportedMessage; } else { httpdHeader(connData, "Content-Encoding", "gzip"); return NULL; } } i++; } return NULL; }
CgiStatus ICACHE_FLASH_ATTR authBasic(HttpdConnData *connData) { const char *unauthorized = "401 Unauthorized."; int no=0; int r; char hdr[(AUTH_MAX_USER_LEN+AUTH_MAX_PASS_LEN+2)*10]; char userpass[AUTH_MAX_USER_LEN+AUTH_MAX_PASS_LEN+2]; char user[AUTH_MAX_USER_LEN]; char pass[AUTH_MAX_PASS_LEN]; if(connData->isConnectionClosed) { //Connection closed. Clean up. return HTTPD_CGI_DONE; } r=httpdGetHeader(connData, "Authorization", hdr, sizeof(hdr)); if (r && strncmp(hdr, "Basic", 5)==0) { r=libesphttpd_base64_decode(strlen(hdr)-6, hdr+6, sizeof(userpass), (unsigned char *)userpass); if (r<0) r=0; //just clean out string on decode error userpass[r]=0; //zero-terminate user:pass string // printf("Auth: %s\n", userpass); while (((AuthGetUserPw)(connData->cgiArg))(connData, no, user, AUTH_MAX_USER_LEN, pass, AUTH_MAX_PASS_LEN)) { //Check user/pass against auth header if (strlen(userpass)==strlen(user)+strlen(pass)+1 && strncmp(userpass, user, strlen(user))==0 && userpass[strlen(user)]==':' && strcmp(userpass+strlen(user)+1, pass)==0) { //Authenticated. Yay! return HTTPD_CGI_AUTHENTICATED; } no++; //Not authenticated with this user/pass. Check next user/pass combo. } } //Not authenticated. Go bug user with login screen. httpdStartResponse(connData, 401); httpdHeader(connData, "Content-Type", "text/plain"); httpdHeader(connData, "WWW-Authenticate", "Basic realm=\""HTTP_AUTH_REALM"\""); httpdEndHeaders(connData); httpdSend(connData, unauthorized, -1); //Okay, all done. return HTTPD_CGI_DONE; }
//This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding //path in the filesystem and if it exists, passes the file through. This simulates what a normal //webserver would do with static files. int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) { EspFsFile *file=connData->cgiData; int len; char buff[1024]; char acceptEncodingBuffer[64]; int isGzip; if (connData->conn==NULL) { //Connection aborted. Clean up. espFsClose(file); return HTTPD_CGI_DONE; } if (file==NULL) { //First call to this cgi. Open the file so we can read it. file=espFsOpen(connData->url); if (file==NULL) { return HTTPD_CGI_NOTFOUND; } // The gzip checking code is intentionally without #ifdefs because checking // for FLAG_GZIP (which indicates gzip compressed file) is very easy, doesn't // mean additional overhead and is actually safer to be on at all times. // If there are no gzipped files in the image, the code bellow will not cause any harm. // Check if requested file was GZIP compressed isGzip = espFsFlags(file) & FLAG_GZIP; if (isGzip) { // Check the browser's "Accept-Encoding" header. If the client does not // advertise that he accepts GZIP send a warning message (telnet users for e.g.) httpdGetHeader(connData, "Accept-Encoding", acceptEncodingBuffer, 64); if (os_strstr(acceptEncodingBuffer, "gzip") == NULL) { //No Accept-Encoding: gzip header present httpdSend(connData, gzipNonSupportedMessage, -1); espFsClose(file); return HTTPD_CGI_DONE; } } connData->cgiData=file; httpdStartResponse(connData, 200); httpdHeader(connData, "Content-Type", httpdGetMimetype(connData->url)); if (isGzip) { httpdHeader(connData, "Content-Encoding", "gzip"); } httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); httpdEndHeaders(connData); return HTTPD_CGI_MORE; } len=espFsRead(file, buff, 1024); if (len>0) espconn_sent(connData->conn, (uint8 *)buff, len); if (len!=1024) { //We're done. espFsClose(file); return HTTPD_CGI_DONE; } else { //Ok, till next time. return HTTPD_CGI_MORE; } }