123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533 |
- #include <sys/uio.h>
- #include "soh.h"
- #include "html.h"
- /******************************************
- This file contains functions for generating
- HTML pages and handling AJAX requests.
- ******************************************/
- /*
- " -> "
- & -> &
- ' -> '
- < -> <
- > -> >
- \ -> \
- */
- static int htmlSpecialChars( const char* str, char* buf, int bufSize ){
-
- int i;
- int res;
- int offset;
-
- offset = 0;
-
- for( i = 0; offset < bufSize; i++ ){
-
- if( str[i] != 34 && str[i] != 38 && str[i] != 39 && str[i] != 60 && str[i] != 62 && str[i] != 92 ){
- buf[offset] = str[i];
-
- if( !str[i] ) return offset;
-
- offset++;
- continue;
- }
-
- if( (offset + 6) >= bufSize ) return -2;
-
- res = sprintf( buf + offset, "&#%i;", str[i] );
- if( res != 5 ){
- perror( "htmlSpecialChars sprintf" );
- return -2;
- }
- offset += 5;
- }
-
- return -2;
- }
- int shareBrowserHtml( struct instance* this ){
-
- int i;
- int res;
- int contentLength;
- char sizeStr[32];
-
- int headersLength;
- char headers[1024];
-
- int pageLength;
- char page[65536];
-
- const char* pagePart1;
- const char* pagePart2;
- const char* pagePart3;
- size_t pagePart1Length;
- size_t pagePart2Length;
- size_t pagePart3Length;
-
- int jsconfigLength;
- char jsconfig[4096];
-
- char tmpbuf[4096];
-
- unsigned char hasFile;
- unsigned char hasRaw;
- unsigned char hasTar;
-
- struct iovec fullPage[6];
- ssize_t fullPageLen;
-
- //init some vars
- contentLength = 0;
- pageLength = 0;
- jsconfigLength = 0;
- hasFile = 0x00;
- hasRaw = 0x00;
- hasTar = 0x00;
- fullPageLen = 0;
-
- pagePart1 = _binary_page_part1_html_start;
- pagePart2 = _binary_page_part2_html_start;
- pagePart3 = _binary_page_part3_html_start;
- pagePart1Length = _binary_page_part1_html_end - _binary_page_part1_html_start;
- pagePart2Length = _binary_page_part2_html_end - _binary_page_part2_html_start;
- pagePart3Length = _binary_page_part3_html_end - _binary_page_part3_html_start;
-
- /********* avaliable utils *********/
-
- //TODO: use for()
-
- //check file avaliable
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( strcmp(this->progs[i].alias, "file") ){
- hasFile = 0xff;
- break;
- }
- }
-
- //check raw avaliable
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( strcmp(this->progs[i].alias, "raw") ){
- hasRaw = 0xff;
- break;
- }
- }
-
- //check tar avaliable
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( !strcmp(this->progs[i].alias, "tar") ){
- hasTar = 0xff;
- break;
- }
- }
-
- /********* js config *********/
-
- //var hasFile = true | false;
- res = sprintf( jsconfig + jsconfigLength, "var hasFile = %s;\n", hasFile ? "true" : "false" );
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
-
- //var hasRaw = true | false;
- res = sprintf( jsconfig + jsconfigLength, "var hasRaw = %s;\n", hasRaw ? "true" : "false" );
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
-
- //var hasTar = true | false;
- res = sprintf( jsconfig + jsconfigLength, "var hasTar = %s;\n", hasTar ? "true" : "false" );
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
-
- //var avaliableCompressors = [ "xz", "bz2", ..., null ];
- res = sprintf( jsconfig + jsconfigLength, "var avaliableCompressors = [ ");
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
-
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( this->progs[i].type == PROGDESC_TYPE_COMPRESSOR ){
- res = sprintf( jsconfig + jsconfigLength, "\"%s\", ", this->progs[i].alias );
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
- }
- }
-
- res = sprintf( jsconfig + jsconfigLength, "null ];\n" );
- if( res < 0 ) goto l_sprintf_error;
- jsconfigLength += res;
-
- /********* root nodes *********/
-
- //convert bytes to readable string
- readableSize( sizeStr, this->root.size );
-
- //replace html special chars in name
- res = htmlSpecialChars( this->root.desc + 1, tmpbuf, sizeof(tmpbuf) );
- if( res < 0 ) goto l_500;
-
- //generate root directory node
- if( (this->root.desc[0] & FILEDESC_TYPE_MASK) == FILEDESC_TYPE_DIR ){
-
- res = sprintf( page + pageLength,
- "<div class=\"nodeListItem\"><input type=\"hidden\" class=\"_dirId\" value=\"%i\">"
- "<span class=\"dirName\" onClick=\"dirIn( this );\">%s</span><small class=\"nodeSize\"> (%s)</small>\n"
- "<div class=\"dirExpander\"></div><div class=\"nodeInfoBlock\">\n",
- 0,//index
- tmpbuf, //name
- sizeStr //size
- );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
-
- //generate root file node
- }else{
-
- res = sprintf( page + pageLength,
- "<div class=\"nodeListItem\"><span class=\"fileName\">%s </span>"
- "<small class=\"nodeSize\"> (%s)</small><div class=\"nodeInfoBlock\">",
- tmpbuf, sizeStr
- );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
-
- //generate download links for case if browser not support js
- if( hasRaw && (this->root.desc[0] & FILEDESC_TYPE_MASK) == FILEDESC_TYPE_FILE ){
-
- if( hasFile ){
- res = sprintf( page + pageLength, "<a class=\"nodeInfoLink\" target=\"_blank\" href=\"download/0/view\">open</a>\n" );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
- }
-
- res = sprintf( page + pageLength, "<a class=\"nodeInfoLink\" target=\"_blank\" href=\"download/0/\">raw</a>\n" );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
-
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( this->progs[i].type != PROGDESC_TYPE_COMPRESSOR ) continue;
-
- res = sprintf( page + pageLength, "<a class=\"nodeInfoLink\" target=\"_blank\" href=\"download/0/%s\">.%s</a>\n",
- this->progs[i].alias, this->progs[i].alias
- );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
- }
- }
- }
-
- //generate download links for case if browser not support js
- if( hasTar ){
- res = sprintf( page + pageLength, "<a class=\"nodeInfoLink\" target=\"_blank\" href=\"download/0/tar\">.tar</a>\n" );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
-
- for( i = 0; this->progs[i].name; i++ ){
- if( !this->progs[i].path ) continue;
- if( this->progs[i].type != PROGDESC_TYPE_COMPRESSOR ) continue;
-
- res = sprintf( page + pageLength, "<a class=\"nodeInfoLink\" target=\"_blank\" href=\"download/0/%s.%s\">%s.%s</a>\n",
- "tar", this->progs[i].alias, "tar", this->progs[i].alias
- );
- if( res < 0 ) goto l_sprintf_error;
- pageLength += res;
- }
- }
-
- res = sprintf( page + pageLength, "</div></div>" );
- if( res < 0 ) goto l_sprintf_error;
- pageLength +=res;
-
-
- /********* generate header *********/
-
- //calculate content length
- contentLength += pagePart1Length;
- contentLength += jsconfigLength;
- contentLength += pagePart2Length;
- contentLength += pageLength;
- contentLength += pagePart3Length;
-
- //create headers
- headersLength = sprintf( headers,
- "%s 200 OK\r\n" //this->protocol
- "Content-Type: text/html; charset=utf-8\r\n"
- "Content-Length: %i\r\n" //contentLength
- "\r\n",
- this->protocol, contentLength
- );
-
- /********* send page *********/
-
- //this is vertor write experiment
-
- //setup vector
- fullPage[0].iov_base = headers; fullPage[0].iov_len = headersLength;
- fullPage[1].iov_base = (void*)pagePart1; fullPage[1].iov_len = pagePart1Length;
- fullPage[2].iov_base = jsconfig; fullPage[2].iov_len = jsconfigLength;
- fullPage[3].iov_base = (void*)pagePart2; fullPage[3].iov_len = pagePart2Length;
- fullPage[4].iov_base = page; fullPage[4].iov_len = pageLength;
- fullPage[5].iov_base = (void*)pagePart3; fullPage[5].iov_len = pagePart3Length;
-
- //calculate total len
- for( i = 0; i < 6; i++ ){
- fullPageLen += fullPage[i].iov_len;
- }
-
- //send full papge
- res = writev( this->clientSocket, fullPage, 6 );
- if( res != fullPageLen ){
- perror( "shareBrowserHtml writev" );
- return -1;
- }
-
- /*
- //send headers
- res = sendData( this->clientSocket, headers, headersLength );
- if( res ) return res;
-
- //send page part 1
- res = sendData( this->clientSocket, pagePart1, pagePart1Length );
- if( res ) return res;
-
- //send js config
- res = sendData( this->clientSocket, jsconfig, jsconfigLength );
- if( res ) return res;
-
- //send page part 2
- res = sendData( this->clientSocket, pagePart2, pagePart2Length );
- if( res ) return res;
-
- //send root nodes
- res = sendData( this->clientSocket, page, pageLength );
- if( res ) return res;
-
- //send page part 3
- res = sendData( this->clientSocket, pagePart3, pagePart3Length );
- if( res ) return res;
- */
-
- printf( "<<< 200 OK.\n" );
-
- return 0;
-
- l_sprintf_error:
- perror( "sprintf" );
-
- l_500:
- return httpSendStatus( this, 500, "Internal server error." );
- }
- int loadNodesBackend( struct instance* this, size_t uriOffset ){
-
- int res;
- long long int i;
- int parseUriRes;
- int headersLength;
- char tmpbuf[4096];
- int pageLength;
- char page[10240];
- struct file_db* nodes;
- long long int nodeIndex;
-
- nodes = &this->root;
-
- /********* search requested node in index *********/
-
- l_uriParseNext:
- //parse uri
- parseUriRes = parserCore( this->uri, '/', tmpbuf, sizeof(tmpbuf), &uriOffset );
- if( parseUriRes < 0 ) goto l_400;
-
- //try read int from uri part
- res = sscanf( tmpbuf, "%lli", &nodeIndex );
- if( res != 1 ) goto l_400;
-
- //search requested node in nodes tree
- for( i = 0; i != nodeIndex; i++ ){
- if( nodes[i].desc[0] & FILEDESC_LAST_FLAG ) goto l_403;
- }
-
- if( parseUriRes ){
-
- //some check before "open" node
- if( (nodes[nodeIndex].desc[0] & FILEDESC_TYPE_MASK) != FILEDESC_TYPE_DIR ) goto l_403;
- if( !nodes[nodeIndex].entries ) goto l_403;
-
- //"open" node
- nodes = nodes[nodeIndex].entries;
-
- i++;
- goto l_uriParseNext;
- }
-
- //set pointer to entries of requested node
- nodes = nodes[nodeIndex].entries;
-
- /********* http headers *********/
-
- //create headers
- headersLength = sprintf( tmpbuf,
- "%s 200 OK\r\n" //this->protocol
- "Content-Type: text/html; charset=utf-8\r\n"
- "\r\n",
- this->protocol
- );
-
- //send headers
- res = sendData( this->clientSocket, tmpbuf, headersLength );
- if( res ) return res;
-
- /********* send node info *********/
-
- //if node has not child nodes
- if( !nodes ){
- res = sendData( this->clientSocket, cnEmptyDir, sizeof(cnEmptyDir) - 1 );
- if( res ) return res;
- goto l_200;
- }
-
- //read and send info about node entries
- i = 0;
-
- l_generateNextCn:
-
- //replace html special chars in name
- res = htmlSpecialChars( nodes[i].desc + 1, tmpbuf, sizeof(tmpbuf) );
- if( res < 0 ) goto l_500;
-
- //generate cn( nodeType, nodeId, nodeName, nodeSize );
- pageLength = sprintf( page, "cn(%i,%lli,\"%s\",%li);",
- (nodes[i].desc[0] & FILEDESC_TYPE_MASK), //node type
- i, //index id
- tmpbuf, //node name
- nodes[i].size //node size
- );
-
- //send node entry
- res = sendData( this->clientSocket, page, pageLength );
- if( res ) return res;
-
- //if this not last, then generate next cn function
- if( !(nodes[i].desc[0] & FILEDESC_LAST_FLAG) ){
- i++;
- goto l_generateNextCn;
- }
-
- l_200:
- printf( "<<< 200 OK.\n" );
- return 0;
-
-
- l_400: return httpSendStatus( this, 400, "Bad request." );
- l_403: return httpSendStatus( this, 403, "Access denied." );
- l_500: return httpSendStatus( this, 500, "Internal server error." );
- }
- static int _htmlDownloadHandler( struct instance* this, size_t uriOffset, long long int* depth ){
-
- int res;
- int uriParseRes;
- char uriPart[32];
- long long int i;
- long long int nodeIndex;
- struct file_db* nodes;
- struct file_db* targetNode;
- struct stat statbuf;
-
- //init some vars
- nodes = &this->root;
- targetNode = NULL;
- *depth = 0;
-
- l_parseUri:
-
- //parse uri
- uriParseRes = parserCore( this->uri, '/', uriPart, sizeof(uriPart), &uriOffset );
- if( uriParseRes < 0 ) goto l_400;
-
- //if this last uri part, then start archiver
- if( !uriParseRes ){
- if( !targetNode ) goto l_400;
- return unixDownloadHandler( this, targetNode, uriPart );
- }
-
- //try convert string to node index
- res = sscanf( uriPart, "%lli", &nodeIndex );
- if( res != 1 ) goto l_400;
-
- //check current node has childs
- if( !nodes ) goto l_403;
-
- //search requested node
- for( i = 0; i != nodeIndex; i++ ){
- if( nodes[i].desc[0] & FILEDESC_LAST_FLAG ) goto l_403;
- }
-
- if( targetNode ){
-
- //check type in our index is dir before open
- if( (targetNode->desc[0] & FILEDESC_TYPE_MASK) != FILEDESC_TYPE_DIR ) goto l_403;
-
- //check type on disk is dir before open
- res = lstat( targetNode->desc + 1, &statbuf);
- if( res < 0 || (statbuf.st_mode & S_IFMT) != S_IFDIR ) goto l_500;
-
- //cd into dir
- res = chdir( targetNode->desc + 1 );
- if( res ){
- perror( "chdir" );
- printf( "FATAL: Cannot open indexed folder: %s\n", targetNode->desc + 1 );
- goto l_500;
- }
-
- //increase depth count
- (*depth)++;
- }
-
- //set pointers
- targetNode = &nodes[nodeIndex];
- nodes = nodes[nodeIndex].entries;
-
- //parse next uri part
- goto l_parseUri;
-
- l_400: return httpSendStatus( this, 400, "Bad request." );
- l_403: return httpSendStatus( this, 403, "Access denied." );
- l_500:
- httpSendStatus( this, 500, "Internal server error." );
- return -2;
- }
- int htmlDownloadHandler( struct instance* this, size_t uriOffset ){
-
- int res;
- long long int depth;
-
- depth = 0;
-
- res = _htmlDownloadHandler( this, uriOffset, &depth );
- if( res < -1 ) return res;
-
- while( depth ){
- res = chdir( "../" );
- if( res ){
- perror( "FATAL: Cannot exit from directory" );
- return -2;
- }
- depth--;
- }
-
- return res;
- }
|