From ad0049b59d24a6d428f89e80c03071c9f3f79e80 Mon Sep 17 00:00:00 2001 From: jsclose <jsclose@umich.edu> Date: Sun, 8 Apr 2018 23:21:41 -0400 Subject: [PATCH] almost working search engine --- CMakeLists.txt | 2 +- server | Bin 35404 -> 40588 bytes site/LinuxTinyServer.cpp | 311 +++++++++++++++++++++++++++++++++++++++ site/index.html | 7 +- site/search.js | 37 +++++ util/LinuxTinyServer.cpp | 294 ------------------------------------ 6 files changed, 354 insertions(+), 297 deletions(-) create mode 100644 site/LinuxTinyServer.cpp create mode 100644 site/search.js delete mode 100644 util/LinuxTinyServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e0904b9..52abead 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -332,7 +332,7 @@ add_executable(testISRQueryTuple ) add_executable(server - util/LinuxTinyServer.cpp) + site/LinuxTinyServer.cpp) add_executable(query-queryLanguage-tests query/queryLanguage/QueryParser.cpp diff --git a/server b/server index 1853a1c9045a2b96477b50772bc0c999dbadab74..daf4121d2e0254d01711eee43a6f8b1785905cce 100755 GIT binary patch literal 40588 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 QYi38Q=TZy*9&K*@f1}^>H2?qr literal 35404 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
GSX}-1<a|?c*_U79-H(?r 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 diff --git a/site/LinuxTinyServer.cpp b/site/LinuxTinyServer.cpp new file mode 100644 index 0000000..b5da6f5 --- /dev/null +++ b/site/LinuxTinyServer.cpp @@ -0,0 +1,311 @@ +// Linux tiny HTTP server. +// Nicole Hamilton nham@umich.edu + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <pthread.h> +#include <fcntl.h> +#include <iostream> +#include <sys/stat.h> +#include <sys/types.h> +#include <string.h> +#include <string> + +#include <cassert> +//using namespace std; +// Multipurpose Internet Mail Extensions (MIME) types + +struct MimetypeMap + { + const char *Extension, + *Mimetype; + }; + +const MimetypeMap MimeTable[] = + { + // List of some of the most common MIME types. + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types + ".aac", "audio/aac", + ".abw", "application/x-abiword", + ".arc", "application/octet-stream", + ".avi", "video/x-msvideo", + ".azw", "application/vnd.amazon.ebook", + ".bin", "application/octet-stream", + ".bz", "application/x-bzip", + ".bz2", "application/x-bzip2", + ".csh", "application/x-csh", + ".css", "text/css", + ".csv", "text/csv", + ".doc", "application/msword", + ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".eot", "application/vnd.ms-fontobject", + ".epub", "application/epub+zip", + ".gif", "image/gif", + ".htm", "text/html", + ".html", "text/html", + ".ico", "image/x-icon", + ".ics", "text/calendar", + ".jar", "application/java-archive", + ".jpeg", "image/jpeg", + ".jpg", "image/jpeg", + ".js", "application/javascript", + ".json", "application/json", + ".mid", "audio/midi", + ".midi", "audio/midi", + ".mpeg", "video/mpeg", + ".mpkg", "application/vnd.apple.installer+xml", + ".odp", "application/vnd.oasis.opendocument.presentation", + ".ods", "application/vnd.oasis.opendocument.spreadsheet", + ".odt", "application/vnd.oasis.opendocument.text", + ".oga", "audio/ogg", + ".ogv", "video/ogg", + ".ogx", "application/ogg", + ".otf", "font/otf", + ".png", "image/png", + ".pdf", "application/pdf", + ".ppt", "application/vnd.ms-powerpoint", + ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".rar", "application/x-rar-compressed", + ".rtf", "application/rtf", + ".sh", "application/x-sh", + ".svg", "image/svg+xml", + ".swf", "application/x-shockwave-flash", + ".tar", "application/x-tar", + ".tif", "image/tiff", + ".tiff", "image/tiff", + ".ts", "application/typescript", + ".ttf", "font/ttf", + ".vsd", "application/vnd.visio", + ".wav", "audio/x-wav", + ".weba", "audio/webm", + ".webm", "video/webm", + ".webp", "image/webp", + ".woff", "font/woff", + ".woff2", "font/woff2", + ".xhtml", "application/xhtml+xml", + ".xls", "application/vnd.ms-excel", + ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xml", "application/xml", + ".xul", "application/vnd.mozilla.xul+xml", + ".zip", "application/zip", + ".3gp", "video/3gpp", + ".3g2", "video/3gpp2", + ".7z", "application/x-7z-compressed" + }; + +const char *Mimetype( const std::string filename ) + { + const char *begin = filename.c_str( ), + *p = begin + filename.length( ) - 1; + // Scan back from the end for an extension. + while ( p >= begin && *p != '.' ) + p--; + if ( *p == '.' ) + { + // Found an extension. Skip over the dot, then + // binary search for a matching mimetype. + + p++; + int i = 0, j = sizeof( MimeTable ) / sizeof( MimetypeMap ) - 1; + while ( i <= j ) + { + int mid = (i + j) / 2, + compare = strcasecmp( p, MimeTable[ mid ].Extension + 1 ); + if ( compare == 0 ) + return MimeTable[ mid ].Mimetype; + if ( compare < 0 ) + j = mid - 1; + else + i = mid + 1; + } + } + + // Anything not matched is an "octet-stream", treated + // as an unknown binary, which can be downloaded. + return "application/octet-stream"; + } + +char *ParseGetRequest( char *request ) + { + // If it's a GET request, null-terminate and + // return the URL. + + if ( strncmp( request, "GET ", 4 ) == 0 ) + { + // Skip the get and any additional white space. + for ( request += 4; *request == ' '; request++ ); + + // Now have the start of the URL. + char *p; + for ( p = request; *p != ' '; p++ ); + *p = 0; // null-terminate the URL. + + return request; // Return the URL. + + } + return nullptr; // Not a GET request. + } + + +char *RootDirectory; + + +off_t FileSize( int f ) + { + struct stat fileInfo; + fstat( f, &fileInfo ); + return fileInfo.st_size; + } + + +void *Talk( void *p ) + { + // Look for a GET message, then reply with the + // requested file. + + char buffer[10240]; + int bytes; + int *pp = (int *) p, s = *pp; + delete pp; + + std::cout << "Starting recv, s = " << s << std::endl; + + while ((bytes = recv( s, buffer, sizeof( buffer ) - 1, 0 )) > 0 ) + { + buffer[ bytes ] = 0; + std::cout << "Request received, s = " << s << std::endl; + std::cout << buffer << std::endl; + char *fullUrl = ParseGetRequest( buffer ); + std::string potentialSearch = std::string( fullUrl, strlen( fullUrl )); + if ( fullUrl ) + { + std::cout << "Requested url = " << fullUrl << std::endl; + std::string search = "/search"; + bool isSearch = true; + for ( int i = 0; i < search.size( ); i++ ) + { + if ( potentialSearch[ i ] != search[ i ] ) + isSearch = false; + break; + + } + if ( isSearch ) + { + + + std::cout << "---Making a search GET---" << std::endl; + std::cout << potentialSearch << std::endl; + } + else + { + + std::string completePath = ""; + std::string Root = std::string( RootDirectory, strlen( RootDirectory )); + std::string cwd = getenv( "PWD" ); + completePath = cwd + Root + fullUrl; + + + //completePath += fullUrl; + std::cout << "Reqested file = " << completePath << std::endl; + + int f = open( completePath.c_str( ), O_RDONLY ); + + if ( f != -1 ) + { + off_t filesize = FileSize( f ); + std::string okMessage = "HTTP/1.1 200 OK\r\n" + "Content-Length: "; + okMessage += std::to_string( filesize ); + okMessage += "\r\nConnection: close\r\nContent-Type: "; + okMessage += Mimetype( completePath ); + okMessage += "\r\n\r\n"; + + std::cout << "Sending" << std::endl; + std::cout << okMessage; + + send( s, okMessage.c_str( ), okMessage.length( ), 0 ); + + while ( bytes = read( f, buffer, sizeof( buffer ))) + send( s, buffer, bytes, 0 ); + + close( f ); + } + else + { + std::string fileNotFound = "HTTP/1.1 404 Not Found\r\n" + "Content-Length: 0\r\n" + "Connection: close\r\n\r\n"; + send( s, fileNotFound.c_str( ), fileNotFound.length( ), 0 ); + } + } + } + } + close( s ); + } + + +void PrintAddress( const sockaddr_in *s, const size_t saLength ) + { + const struct in_addr *ip = &s->sin_addr; + uint32_t a = ntohl( ip->s_addr ); + + std::cout << "Host address length = " << saLength << " bytes" << std::endl; + std::cout << "Family = " << s->sin_family << + ", port = " << ntohs( s->sin_port ) << + ", address = " << (a >> 24) << '.' << + ((a >> 16) & 0xff) << '.' << + ((a >> 8) & 0xff) << '.' << + (a & 0xff) << std::endl; + } + + +int main( int argc, char **argv ) + { + if ( argc != 3 ) + { + std::cerr << "Usage: LinuxTinyServer port rootdirectory" << std::endl; + return 1; + } + + int port = atoi( argv[ 1 ] ); + RootDirectory = argv[ 2 ]; + + // Create TCP/IP sockets for listening and talking. + + struct sockaddr_in listenAddress, talkAddress; + socklen_t talkAddressLength; + int listenSocket, talkSocket; + + memset( &listenAddress, 0, sizeof( listenAddress )); + memset( &talkAddress, 0, sizeof( talkAddress )); + + listenAddress.sin_family = AF_INET; + listenAddress.sin_port = htons( port ); + listenAddress.sin_addr.s_addr = htonl( INADDR_ANY ); + + listenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); + assert( listenSocket != -1 ); + + int bindResult = bind( listenSocket, (sockaddr *) &listenAddress, sizeof( listenAddress )); + assert( bindResult == 0 ); + + int listenResult = listen( listenSocket, SOMAXCONN ); + assert( listenResult == 0 ); + + std::cout << "Listening" << std::endl; + PrintAddress( &listenAddress, sizeof( listenAddress )); + + while ((talkAddressLength = sizeof( talkAddress ), + talkSocket = accept( listenSocket, (sockaddr *) &talkAddress, + &talkAddressLength )) && talkSocket != -1 ) + { + std::cout << "Connection accepted, talkSocket = " << talkSocket << std::endl; + PrintAddress( &talkAddress, talkAddressLength ); + pthread_t child; + pthread_create( &child, nullptr, Talk, new int( talkSocket )); + } + + close( listenSocket ); + } diff --git a/site/index.html b/site/index.html index 98d0e05..476ac8f 100644 --- a/site/index.html +++ b/site/index.html @@ -1,6 +1,9 @@ +<head> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> +<script src="search.js"></script> +</head> <!------ Include the above in your HEAD tag ----------> <div class="container"> @@ -8,9 +11,9 @@ <div class="col-sm-6 col-sm-offset-3"> <div id="imaginary_container"> <div class="input-group stylish-input-group"> - <input type="text" class="form-control" placeholder="Search" > + <input type="text" class="form-control" id="query" placeholder="Search" > <span class="input-group-addon"> - <button type="submit"> + <button id = "search" type="submit"> <span class="glyphicon glyphicon-search"></span> </button> </span> diff --git a/site/search.js b/site/search.js new file mode 100644 index 0000000..c2cd52c --- /dev/null +++ b/site/search.js @@ -0,0 +1,37 @@ +$(function () { + + $("#search").click(get_request); + + + +}); + + + + +function get_request(artist_name){ + $query = $("#query").val(); + + + $.ajax({ + url: "/search", + type: 'GET', + contentType: "text/plain", + data: $query, + dataType: 'json', + success: function (data) { + + + console.log("Pass"); + console.log("Data") + + + }, + error: function (data) { + console.log(data); + + } + }); + + +}; \ No newline at end of file diff --git a/util/LinuxTinyServer.cpp b/util/LinuxTinyServer.cpp deleted file mode 100644 index ad4a103..0000000 --- a/util/LinuxTinyServer.cpp +++ /dev/null @@ -1,294 +0,0 @@ -// Linux tiny HTTP server. -// Nicole Hamilton nham@umich.edu - -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netdb.h> -#include <pthread.h> -#include <fcntl.h> -#include <iostream> -#include <sys/stat.h> -#include <sys/types.h> -#include <string.h> -#include <string> -#include <cassert> -//using namespace std; -// Multipurpose Internet Mail Extensions (MIME) types - -struct MimetypeMap - { - const char *Extension, - *Mimetype; - }; - -const MimetypeMap MimeTable[ ] = - { - // List of some of the most common MIME types. - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types - ".aac", "audio/aac", - ".abw", "application/x-abiword", - ".arc", "application/octet-stream", - ".avi", "video/x-msvideo", - ".azw", "application/vnd.amazon.ebook", - ".bin", "application/octet-stream", - ".bz", "application/x-bzip", - ".bz2", "application/x-bzip2", - ".csh", "application/x-csh", - ".css", "text/css", - ".csv", "text/csv", - ".doc", "application/msword", - ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", - ".eot", "application/vnd.ms-fontobject", - ".epub", "application/epub+zip", - ".gif", "image/gif", - ".htm", "text/html", - ".html", "text/html", - ".ico", "image/x-icon", - ".ics", "text/calendar", - ".jar", "application/java-archive", - ".jpeg", "image/jpeg", - ".jpg", "image/jpeg", - ".js", "application/javascript", - ".json", "application/json", - ".mid", "audio/midi", - ".midi", "audio/midi", - ".mpeg", "video/mpeg", - ".mpkg", "application/vnd.apple.installer+xml", - ".odp", "application/vnd.oasis.opendocument.presentation", - ".ods", "application/vnd.oasis.opendocument.spreadsheet", - ".odt", "application/vnd.oasis.opendocument.text", - ".oga", "audio/ogg", - ".ogv", "video/ogg", - ".ogx", "application/ogg", - ".otf", "font/otf", - ".png", "image/png", - ".pdf", "application/pdf", - ".ppt", "application/vnd.ms-powerpoint", - ".pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation", - ".rar", "application/x-rar-compressed", - ".rtf", "application/rtf", - ".sh", "application/x-sh", - ".svg", "image/svg+xml", - ".swf", "application/x-shockwave-flash", - ".tar", "application/x-tar", - ".tif", "image/tiff", - ".tiff", "image/tiff", - ".ts", "application/typescript", - ".ttf", "font/ttf", - ".vsd", "application/vnd.visio", - ".wav", "audio/x-wav", - ".weba", "audio/webm", - ".webm", "video/webm", - ".webp", "image/webp", - ".woff", "font/woff", - ".woff2", "font/woff2", - ".xhtml", "application/xhtml+xml", - ".xls", "application/vnd.ms-excel", - ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ".xml", "application/xml", - ".xul", "application/vnd.mozilla.xul+xml", - ".zip", "application/zip", - ".3gp", "video/3gpp", - ".3g2", "video/3gpp2", - ".7z", "application/x-7z-compressed" - }; - -const char *Mimetype( const std::string filename ) - { - const char *begin = filename.c_str( ), - *p = begin + filename.length( ) - 1; - // Scan back from the end for an extension. - while ( p >= begin && *p != '.' ) - p--; - if ( *p == '.' ) - { - // Found an extension. Skip over the dot, then - // binary search for a matching mimetype. - - p++; - int i = 0, j = sizeof( MimeTable )/sizeof( MimetypeMap ) - 1; - while ( i <= j ) - { - int mid = ( i + j )/2, - compare = strcasecmp( p, MimeTable[ mid ].Extension + 1 ); - if ( compare == 0 ) - return MimeTable[ mid ].Mimetype; - if ( compare < 0 ) - j = mid - 1; - else - i = mid + 1; - } - } - - // Anything not matched is an "octet-stream", treated - // as an unknown binary, which can be downloaded. - return "application/octet-stream"; - } - -char *ParseGetRequest( char *request ) - { - // If it's a GET request, null-terminate and - // return the URL. - - if ( strncmp( request, "GET ", 4 ) == 0 ) - { - // Skip the get and any additional white space. - for ( request += 4; *request == ' '; request++ ) - ; - - // Now have the start of the URL. - char *p; - for ( p = request; *p != ' '; p++ ) - ; - *p = 0; // null-terminate the URL. - - return request; // Return the URL. - - } - return nullptr; // Not a GET request. - } - - -char *RootDirectory; - - -off_t FileSize( int f ) - { - struct stat fileInfo; - fstat( f, &fileInfo ); - return fileInfo.st_size; - } - - -void *Talk( void *p ) - { - // Look for a GET message, then reply with the - // requested file. - - char buffer[ 10240 ]; - int bytes; - int *pp = ( int * )p, s = *pp; - delete pp; - - std::cout << "Starting recv, s = " << s << std::endl; - - while ( ( bytes = recv( s, buffer, sizeof( buffer ) - 1, 0 ) ) > 0 ) - { - buffer[ bytes ] = 0; - std::cout << "Request received, s = " << s << std::endl; - std::cout << buffer << std::endl; - char *fullUrl = ParseGetRequest( buffer ); - if ( fullUrl ) - { - std::cout << "Requested url = " << fullUrl << std::endl; - if( strcmp(fullUrl, "/query") == 0) - { - std::cout << "GET REQUEST" << std::endl; - - } - - - std::string completePath = strcat(getenv( "PWD" ), (RootDirectory)); - //completePath += fullUrl; - std::cout << "Reqested file = " << completePath << std::endl; - - int f = open( completePath.c_str( ), O_RDONLY ); - - if ( f != -1 ) - { - off_t filesize = FileSize( f ); - std::string okMessage = "HTTP/1.1 200 OK\r\n" - "Content-Length: "; - okMessage += std::to_string( filesize ); - okMessage += "\r\nConnection: close\r\nContent-Type: "; - okMessage += Mimetype( completePath ); - okMessage += "\r\n\r\n"; - - std::cout << "Sending" << std::endl; - std::cout << okMessage; - - send( s, okMessage.c_str( ), okMessage.length( ), 0 ); - - while ( bytes = read( f, buffer, sizeof( buffer ) ) ) - send( s, buffer, bytes, 0 ); - - close( f ); - } - else - { - std::string fileNotFound = "HTTP/1.1 404 Not Found\r\n" - "Content-Length: 0\r\n" - "Connection: close\r\n\r\n"; - send( s, fileNotFound.c_str( ), fileNotFound.length( ), 0 ); - } - } - } - - close( s ); - } - - -void PrintAddress( const sockaddr_in *s, const size_t saLength ) - { - const struct in_addr *ip = &s->sin_addr; - uint32_t a = ntohl( ip->s_addr ); - - std::cout << "Host address length = " << saLength << " bytes" <<std:: endl; - std::cout << "Family = " << s->sin_family << - ", port = " << ntohs( s->sin_port ) << - ", address = " << ( a >> 24 ) << '.' << - ( ( a >> 16 ) & 0xff ) << '.' << - ( ( a >> 8 ) & 0xff ) << '.' << - ( a & 0xff ) << std::endl; - } - - -int main( int argc, char **argv ) - { - if ( argc != 3 ) - { - std::cerr << "Usage: LinuxTinyServer port rootdirectory" << std::endl; - return 1; - } - - int port = atoi( argv[ 1 ] ); - RootDirectory = argv[ 2 ]; - - // Create TCP/IP sockets for listening and talking. - - struct sockaddr_in listenAddress, talkAddress; - socklen_t talkAddressLength; - int listenSocket, talkSocket; - - memset( &listenAddress, 0, sizeof( listenAddress ) ); - memset( &talkAddress, 0, sizeof( talkAddress ) ); - - listenAddress.sin_family = AF_INET; - listenAddress.sin_port = htons( port ); - listenAddress.sin_addr.s_addr = htonl( INADDR_ANY ); - - listenSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP ); - assert( listenSocket != -1 ); - - int bindResult = bind( listenSocket, ( sockaddr * ) &listenAddress, sizeof( listenAddress ) ); - assert( bindResult == 0 ); - - int listenResult = listen( listenSocket, SOMAXCONN ); - assert( listenResult == 0 ); - - std::cout << "Listening" << std::endl; - PrintAddress( &listenAddress, sizeof( listenAddress ) ); - - while ( ( talkAddressLength = sizeof( talkAddress ), - talkSocket = accept( listenSocket, ( sockaddr * )&talkAddress, - &talkAddressLength ) ) && talkSocket != -1 ) - { - std::cout << "Connection accepted, talkSocket = " << talkSocket << std::endl; - PrintAddress( &talkAddress, talkAddressLength ); - pthread_t child; - pthread_create( &child, nullptr, Talk, new int( talkSocket ) ); - } - - close( listenSocket ); - } -- GitLab