int StripGETRequestQueryAndFragment(char * request, unsigned int maxQueryLength) { if (request==0) { errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT); return 0;} unsigned int length=strlen(request); if (length==0) { errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT); return 0; } if (length>maxQueryLength) { length=maxQueryLength; } unsigned int i=0,fragment_pos=length; while ( (i<length) && (request[i]!='?') /*Query start character*/) { if (request[i]=='#' /*Fragment start character*/ ) { fragment_pos=i; } ++i; } //fprintf(stderr,"Searching for Query : Request has a %u size , fragment at pos %u/%u \n",length,fragment_pos,length); if (fragment_pos<length) { request[fragment_pos]=0; /*Disregard any fragments , they are for the client only.. */ } if (i==length) { return 0; } //<- could not find a .. if (i+1>=length) { return 0; } //<- found the question mark at i BUT it is the last character so no extension is possible..! //char * start_of_query = &request[i+1]; // do not include ? ( question mark ) //Null Terminate request[i]=0; //fprintf(stderr,"GET Request ( %s ) has a query inlined ( %s ) \n",request,query); return 1; }
void cParser::onError(void) { skipToEnd(); char buffer[256]; sprintf_s(buffer, 256, "行 %d : ",m_curLine+1); m_errorDesc = buffer; if (errorID() == 1) { m_errorDesc += "在尝试赋值的时候,没有得到任何可赋值的变量。"; } else if (errorID() == 2) { m_errorDesc += "同一行上出现了两个变量名 :"; m_errorDesc += m_variable; m_errorDesc += " 和 "; m_errorDesc += m_curVariable; } else if (errorID() == 3) { m_errorDesc += "非法变量名。"; } else { m_errorDesc += "未知错误。"; } testOutput(m_errorDesc); m_curVariable.clear(); m_variable.clear(); setError(0); }
unsigned int ServerThreads_DropRootUID() { if (ENABLE_DROPPING_UID_ALWAYS ) { /* We fall through and change UID , as a mandatory step.. */} else if (ENABLE_DROPPING_ROOT_UID_IF_ROOT) { /*Check if we are root */ if (getuid()>=1000) { /*Non root id , we can skip dropping our UID with this configuration..*/ return 0; } //If we fell through it means we are root and dropping root when root is enabled so the code that follows will alter our uid.. } else { if (getuid()<1000) { errorID(ASV_ERROR_RUNNING_AS_ROOT); } return 0; } char command_to_get_uid[MAX_FILE_PATH]={0}; snprintf(command_to_get_uid,MAX_FILE_PATH,"id -u %s",USERNAME_UID_FOR_DAEMON); FILE * fp = popen(command_to_get_uid, "r"); if (fp == 0 ) { fprintf(stderr,"Failed to get our user id ( trying to drop root UID ) \n"); return 0; } char output[POPEN_BUFFER_SIZE]={0}; /* Read the output a line at a time - output it. */ unsigned int i=0; //Why is this needed ? while (fgets(output,POPEN_BUFFER_SIZE , fp) != 0) { ++i; /*fprintf(stderr,"\n\nline %u = %s \n",i,output);*/ break; } /* close */ pclose(fp); int non_root_uid = atoi(output); if (non_root_uid<1000) { fprintf(stderr,"The user set in USERNAME_UID_FOR_DAEMON=\"%s\" is also root (his uid is %d)\n",USERNAME_UID_FOR_DAEMON,non_root_uid); if (CHANGE_TO_UID<1000) { errorID(ASV_ERROR_FAILED_TO_DROP_ROOT_UID); non_root_uid=NON_ROOT_UID_IF_USER_FAILS; } else { non_root_uid=CHANGE_TO_UID; } } fprintf(stderr,"setuid(%d);\n",non_root_uid); return setuid(non_root_uid); // Non Root UID :-P }
int ReducePathSlashes_Inplace(char * filename) { //This piece of code removes excess slashes from resource strings in place //For example the string public_html/////test.html will become public_html/test.html //While extra slashes cause no side effects on fopen calls etc , they interfere with the //hashing functions because public_html//test.html yields a different hash than public_html/test.html .. //This in turn means cache misses happening without any reason and the cache growing larger for files already //contained in it , that is why it is worth it to reduce slashes for every incoming request even if it means //growing the incoming string processing surface .. //fprintf(stderr,"ReducePathSlashes_Inplace(%s) needs thorough testing .. :P\n",filename); unsigned int length=strlen(filename); unsigned int i=0,offset=0; while (i+offset<length) { if ( filename[i+offset]=='/') { unsigned int z=i+offset+1; while ((z<length)&&(filename[z]=='/')) { ++offset; ++z; } if (z>i+offset+1) { //We increased the offset ..! ++i; // We dont want to hurt the first slash ..! //The next character though should be eliminated if offset changed } } if ( (offset>0)&&(i+offset<length) ) { filename[i]=filename[i+offset]; } ++i; } if (strstr(filename,"//")!=0) { errorID(ASV_ERROR_REDUCE_SLASHSES_FAILED); } if (offset>0) { //We have reduced the total slashes..! //Append new null termination filename[length-offset]=0; //fprintf(stderr,"String shortened to %s.. :P\n",filename); return 1; } //fprintf(stderr,"String (%s) was not changed \n",filename); return 0; }
int setSocketTimeouts(int clientSock) { int errorSettingTimeouts = 1; #if USE_TIMEOUTS struct timeval timeout; //We dont need to initialize here , since we initialize on the next step timeout.tv_sec = (unsigned int) varSocketTimeoutREAD_seconds; timeout.tv_usec = 0; if (setsockopt (clientSock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT); errorSettingTimeouts=0; } timeout.tv_sec = (unsigned int) varSocketTimeoutWRITE_seconds; timeout.tv_usec = 0; if (setsockopt (clientSock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT); errorSettingTimeouts=0; } #else #error "It is a terrible idea not to use socket timeouts , this will make the webserver susceptible to DoS attacks..!" #endif // USE_TIMEOUTS return errorSettingTimeouts; }
int getSocketIPAddress(struct AmmServer_Instance * instance , int clientSock , char * ipstr , unsigned int ipstrLength,unsigned int * port) { //Lets find out who we are talking to , and if we want to deny him service or not..! socklen_t len=0; struct sockaddr_storage addr; ipstr[0]=0; strcpy(ipstr,"0.0.0.0"); *port=0; len = sizeof addr; if ( getpeername(clientSock, (struct sockaddr*)&addr, &len) == 0 ) { const char * resolveResult = 0; // deal with both IPv4 and IPv6: if (addr.ss_family == AF_INET) { struct sockaddr_in *s = (struct sockaddr_in *)&addr; *port = ntohs(s->sin_port); resolveResult = inet_ntop(AF_INET, &s->sin_addr, ipstr,ipstrLength); } else { // AF_INET6 struct sockaddr_in6 *s = (struct sockaddr_in6 *)&addr; *port = ntohs(s->sin6_port); resolveResult = inet_ntop(AF_INET6, &s->sin6_addr, ipstr,ipstrLength); } if (resolveResult == 0) { errorID(ASV_ERROR_INNETOP_FAILED); //This could be a reason to drop this connection! switch ( errno ) { case EAFNOSUPPORT : warning("The af argument is invalid.\n"); break; case ENOSPC : warning("The size of the inet_ntop() result buffer is inadequate.\n"); break; } } fprintf(stderr,"%s: Peer IP address: %s , port %d \n", instance->instanceName , ipstr,*port); } else { warning("Could not get peer name..!"); //This could be a reason to drop this connection! switch ( errno ) { case EBADF : warning("The argument sockfd is not a valid descriptor."); break; case EFAULT : warning("The addr argument points to memory not in a valid part of the process address space."); break; case EINVAL : warning("addrlen is invalid (e.g., is negative)."); break; case ENOBUFS : warning("Insufficient resources were available in the system to perform the operation."); break; case ENOTCONN : warning("The socket is not connected."); break; case ENOTSOCK : warning("The argument sockfd is a file, not a socket."); break; }; return 0; } return 1; // <- TODO add IPv4 , IPv6 IP here }
int _GENERIC_cpy(const char * what2copy,unsigned int what2copySize,char * where2copy,unsigned int maxSizeWhere2Copy) { if (what2copy==0) { return 0; } if (where2copy==0) { return 0; } if (what2copySize+1>maxSizeWhere2Copy) { errorID(ASV_ERROR_NOT_ENOUGH_MEMORY_ALLOCATED); return 0; } snprintf(where2copy,maxSizeWhere2Copy,"%s",what2copy); return 1; }
//You should use AmmCLient instead of this shitty code..! char * RequestHTTPWebPage(struct AmmServer_Instance * instance,char * hostname,unsigned int port,char * filename,unsigned int max_content) { int sockfd; struct hostent *he=0; struct sockaddr_in their_addr; if ((he=gethostbyname(hostname)) == 0) { fprintf(stderr,"Error getting host (%s) by name \n",hostname); return 0; } else { printf("Client-The remote host is: %s\n",hostname); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { errorID(ASV_ERROR_FAILED_TO_SOCKET); return 0; } else { printf("Client socket ok\n"); } // host byte order their_addr.sin_family = AF_INET; // short, network byte order printf("Server-Using %s:%u...\n",hostname,port); their_addr.sin_port = htons(port); their_addr.sin_addr = *((struct in_addr *)he->h_addr); // zero the rest of the struct memset(&(their_addr.sin_zero), 0 , 8); // '\0' if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1) { errorID(ASV_ERROR_FAILED_TO_CONNECT); return 0; } else { printf("Starting Request for filename %s \n",filename); } #if USE_TIMEOUTS struct timeval timeout; timeout.tv_sec = (unsigned int) varSocketTimeoutREAD_seconds; timeout.tv_usec = 0; if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { fprintf(stderr,"Warning : Could not set socket Receive timeout \n"); } timeout.tv_sec = (unsigned int) varSocketTimeoutWRITE_seconds; timeout.tv_usec = 0; if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0) { fprintf(stderr,"Warning : Could not set socket Send timeout \n"); } #else #error "It is a terrible idea not to use socket timeouts , this will make the webserver susceptible to DoS attacks..!" #endif // USE_TIMEOUTS unsigned long bufferSize = (max_content+1) * sizeof(char); char * buffer = (char*) malloc(bufferSize); if (buffer!=0) { snprintf(buffer,max_content,"GET /%s HTTP/1.1\r\nHost: %s\r\n\r\n",filename,hostname); struct HTTPTransaction transaction={0}; //This is a dummy call and does not need ASRV_StartSession transaction.clientSock = sockfd; int opres = ASRV_Send(instance,&transaction,buffer,strlen(buffer),MSG_WAITALL|MSG_NOSIGNAL); //Send filesize as soon as we've got it if (opres<=0) { fprintf(stderr,"Error Sending Request data\n"); } else { buffer[0]=0; opres = recv(sockfd,buffer,max_content,0); if (opres<=0) { fprintf(stderr,"Error Receiving Request data\n"); } } safeFree(buffer,bufferSize); } close(sockfd); /** @bug : Check for success or failure on RequestHTTPWebPage and return an appropriate return value */ return 0; }
int GetContentTypeForExtension(const char * theextension,char * content_type,unsigned int contentTypeLength) { //fprintf(stderr,"Resolving Extension %s , length %u \n",theextension,theextensionLength ); if (contentTypeLength<29) { errorID(ASV_ERROR_CALL_WITHOUT_ENOUGH_INPUT); fprintf(stderr,"GetContentTypeForExtension called with a very small buffer ( %u bytes ) \n",contentTypeLength ); return 0; } unsigned int theextensionLength = strlen(theextension); //http://www.iana.org/assignments/media-types/text/index.html unsigned int ext=scanFor_textFiles(theextension,theextensionLength); switch (ext) { case TEXTFILES_HTML : strcpy(content_type,"text/html"); content_type[9]=0; return 1; break; case TEXTFILES_HTM : strcpy(content_type,"text/html"); content_type[9]=0; return 1; break; case TEXTFILES_CSS : strcpy(content_type,"text/css"); content_type[8]=0; return 1; break; case TEXTFILES_TXT : strcpy(content_type,"text/txt"); content_type[8]=0; return 1; break; case TEXTFILES_DOC : strcpy(content_type,"text/doc"); content_type[8]=0; return 1; break; case TEXTFILES_RTF : strcpy(content_type,"text/rtf"); content_type[8]=0; return 1; break; case TEXTFILES_ODF : strcpy(content_type,"text/odf"); content_type[8]=0; return 1; break; case TEXTFILES_ODT : strcpy(content_type,"text/odt"); content_type[8]=0; return 1; break; }; //http://www.iana.org/assignments/media-types/image/index.html ext=scanFor_imageFiles(theextension,theextensionLength); switch (ext) { case IMAGEFILES_GIF : strcpy(content_type,"image/gif"); content_type[9]=0; return 1; break; case IMAGEFILES_PNG : strcpy(content_type,"image/png"); content_type[9]=0; return 1; break; case IMAGEFILES_JPG : case IMAGEFILES_JPEG : strcpy(content_type,"image/jpg"); content_type[9]=0; return 1; break; case IMAGEFILES_WEBP : strcpy(content_type,"image/webp"); content_type[10]=0; return 1; break; case IMAGEFILES_BMP : strcpy(content_type,"image/bmp"); content_type[9]=0; return 1; break; case IMAGEFILES_TIFF : strcpy(content_type,"image/tiff"); content_type[10]=0; return 1; break; case IMAGEFILES_DIB : strcpy(content_type,"image/dib"); content_type[9]=0; return 1; break; case IMAGEFILES_RLE : strcpy(content_type,"image/rle"); content_type[9]=0; return 1; break; case IMAGEFILES_J2C : strcpy(content_type,"image/j2c"); content_type[9]=0; return 1; break; case IMAGEFILES_ICO : strcpy(content_type,"image/ico"); content_type[9]=0; return 1; break; case IMAGEFILES_PPM : strcpy(content_type,"image/ppm"); content_type[9]=0; return 1; break; case IMAGEFILES_PNM : strcpy(content_type,"image/pnm"); content_type[9]=0; return 1; break; case IMAGEFILES_RAW : strcpy(content_type,"image/raw"); content_type[9]=0; return 1; break; case IMAGEFILES_SVG : strcpy(content_type,"image/svg+xml"); content_type[13]=0; return 1; break; }; //http://www.iana.org/assignments/media-types/video/index.html ext=scanFor_videoFiles(theextension,theextensionLength); switch (ext) { case VIDEOFILES_AVI : strcpy(content_type,"video/mp4"); content_type[9]=0; return 1; break; case VIDEOFILES_MPEG4 : strcpy(content_type,"video/mp4"); content_type[9]=0; return 1; break; case VIDEOFILES_MPEG : strcpy(content_type,"video/mp4"); content_type[9]=0; return 1; break; case VIDEOFILES_MP4 : strcpy(content_type,"video/mp4"); content_type[9]=0; return 1; break; case VIDEOFILES_OGV : strcpy(content_type,"video/ogv"); content_type[9]=0; return 1; break; case VIDEOFILES_WEBM : strcpy(content_type,"video/webm"); content_type[10]=0; return 1; break; case VIDEOFILES_MKV : strcpy(content_type,"video/mkv"); content_type[9]=0; return 1; break; case VIDEOFILES_3GP : strcpy(content_type,"video/3gp"); content_type[9]=0; return 1; break; case VIDEOFILES_H263 : strcpy(content_type,"video/h263"); content_type[10]=0;return 1; break; case VIDEOFILES_H264 : strcpy(content_type,"video/h264"); content_type[10]=0;return 1; break; case VIDEOFILES_FLV : strcpy(content_type,"video/x-flv"); content_type[11]=0; return 1; break; }; //http://www.iana.org/assignments/media-types/audio/index.html ext=scanFor_audioFiles(theextension,theextensionLength); switch (ext) { case AUDIOFILES_MP3 : strcpy(content_type,"audio/mp3"); content_type[9]=0; return 1; break; case AUDIOFILES_WAV : strcpy(content_type,"audio/wav"); content_type[9]=0; return 1; break; case AUDIOFILES_MID : strcpy(content_type,"audio/mid"); content_type[9]=0; return 1; break; case AUDIOFILES_OGG : strcpy(content_type,"audio/ogg"); content_type[9]=0; return 1; break; case AUDIOFILES_VOC : strcpy(content_type,"audio/voc"); content_type[9]=0; return 1; break; case AUDIOFILES_AU : strcpy(content_type,"audio/au"); content_type[8]=0; return 1; break; }; //http://www.iana.org/assignments/media-types/application/index.html ext=scanFor_applicationFiles(theextension,theextensionLength); switch (ext) { case APPLICATIONFILES_EXE : case APPLICATIONFILES_DLL : case APPLICATIONFILES_SCR : case APPLICATIONFILES_CPL : strcpy(content_type,"application/exe"); content_type[15]=0; return 1; break; case APPLICATIONFILES_SWF : strcpy(content_type,"application/x-shockwave-flash"); content_type[29]=0; return 1; break; case APPLICATIONFILES_PDF : strcpy(content_type,"application/pdf"); content_type[15]=0; return 1; break; }; ext=scanFor_archiveFiles(theextension,theextensionLength); switch (ext) { case ARCHIVEFILES_GZ : strcpy(content_type,"application/gzip"); content_type[16]=0; return 1; break; case ARCHIVEFILES_TAR : strcpy(content_type,"application/x-tar"); content_type[17]=0; return 1; break; case ARCHIVEFILES_TGZ : strcpy(content_type,"application/gnutar"); content_type[18]=0; return 1; break; case ARCHIVEFILES_ZIP : strcpy(content_type,"application/zip"); content_type[15]=0; return 1; break; case ARCHIVEFILES_JAR : case ARCHIVEFILES_7Z : case ARCHIVEFILES_AR : case ARCHIVEFILES_BZ2 : case ARCHIVEFILES_CBZ : case ARCHIVEFILES_CPIO : case ARCHIVEFILES_ISO : case ARCHIVEFILES_LZMA : case ARCHIVEFILES_TAR_7Z : case ARCHIVEFILES_TAR_Z : case ARCHIVEFILES_TAR_GZ : case ARCHIVEFILES_TAR_BZ2 : case ARCHIVEFILES_TAR_BZ : case ARCHIVEFILES_TAR_LZ : case ARCHIVEFILES_TAR_LZMA : case ARCHIVEFILES_TAR_XZ : case ARCHIVEFILES_XZ : strcpy(content_type,"application/octet-stream"); content_type[24]=0; return 1; break; }; fprintf(stderr,"Could not find extension type for extension %s \n",theextension); return 0; }
void * ServeClientAfterUnpackingThreadMessage(void * ptr) { // We first have to store the context variables we got through our struct PassToHTTPThread // so we first need to do that struct PassToHTTPThread * context = (struct PassToHTTPThread *) ptr; if (context->keep_var_on_stack!=1) { errorID(ASV_ERROR_FAILED_TO_PASS_THREAD_CONTEXT); fprintf(stderr,"Bad new thread context is pointing to %p\n",context); return 0; } //This is the structure that holds all the state of the current ServeClient transaction struct AmmServer_Instance * instance = context->instance; struct HTTPTransaction transaction={0}; // This should get free'ed once it isn't needed any more see FreeHTTPHeader call! //int close_connection=0; // <- if this is set it means Serve Client must stop transaction.instance=instance; //memset(&transaction->incomingHeader,0,sizeof(struct HTTPHeader)); transaction.incomingHeader.headerRAW=0; transaction.incomingHeader.headerRAWSize=0; // In order for each thread to (in theory) be able to serve a different virtual website // we declare the webserver_root etc here and we copy the value from the thread spawning function // This creates a little code clutter but it is for the best..! transaction.prespawnedThreadFlag=context->pre_spawned_thread; transaction.clientSock=context->clientsock; transaction.threadID = context->thread_id; if (!transaction.prespawnedThreadFlag) { int i = pthread_detach(instance->threads_pool[transaction.threadID]); if (i!=0) { switch (i) { case EINVAL : warning("While trying to detach thread , The implementation has detected that the value specified by thread does not refer to a joinable thread."); break; case ESRCH : warning("While trying to detach thread , No thread could be found corresponding to that specified by the given thread ID."); break; }; } } fprintf(stderr,"Now signaling we are ready (%u)\n",transaction.threadID); context->keep_var_on_stack=2; //This signals that the thread has processed the message it received..! fprintf(stderr,"Passing message to HTTP thread is done (%u)\n",transaction.threadID); ASRV_StartSession(instance,&transaction); //int i= ServeClientInternal(instance,&transaction); ASRV_StopSession(instance,&transaction); /* //Removed to reduce spam..! if (i) { //SUCCESS } else { //FAILURE warning("Could not successfully serve client.."); } */ return 0; }
int ServeClientInternal(struct AmmServer_Instance * instance , struct HTTPTransaction * transaction) { if (instance==0) { errorID(ASV_ERROR_INSTANCE_NOT_ALLOCATED); return 0; } else { /*fprintf(stderr,"ServeClient instance pointing @ %p \n",instance);*/ } if (!setSocketTimeouts(transaction->clientSock)) { errorID(ASV_ERROR_COULD_NOT_SET_SOCKET_TIMEOUT); fprintf(stderr,"This means something weird is going on , skipping everything"); return 0; } transaction->clientListID = findOutClientIDOfPeer(instance ,transaction->clientSock); //----------------------------- ---------------------------- ---------------------------- // Check if client is banned //----------------------------- ---------------------------- ---------------------------- int clientIsBanned = clientList_isClientBanned(instance->clientList,transaction->clientListID); //----------------------------- ---------------------------- ---------------------------- if (!clientIsBanned) { //If client is ok go ahead to serve him.. unsigned int keepAliveShots = 1; while ( ( ServeClientKeepAliveLoop(instance,transaction) ) && (instance->server_running) ) { //fprintf(stderr,"Another KeepAlive Loop Served ( %u ) \n",keepAliveShots); ++keepAliveShots; clientIsBanned = clientList_isClientBanned(instance->clientList,transaction->clientListID); if (clientIsBanned) { warningID(ASV_WARNING_CLIENT_DENIED_ACCESS); SendErrorCodeHeader(instance,transaction,403 /*Forbidden*/,"403.html",instance->templates_root); break; } } } //----------------------------- ---------------------------- ---------------------------- //fprintf(stderr,"Done with client / Closing Socket ( %u ) ..\n",transaction->clientSock); close(transaction->clientSock); // shutdown(transaction->clientSock,SHUT_RDWR); if (transaction->incomingHeader.headerRAW!=0) { //fprintf(stderr,"Done with client / Freeing incoming memory..\n"); safeFree(transaction->incomingHeader.headerRAW,transaction->incomingHeader.headerRAWSize); transaction->incomingHeader.headerRAW=0; } //fprintf(stderr,"closed\n"); if (!transaction->prespawnedThreadFlag) { //If we are running in a prespawned thread it is wrong to count this thread as a *dynamic* one that just stopped ! //Clear thread id handler and we can gracefully exit..! ( LOCKLESS OPERATION) if (instance->threads_pool[transaction->threadID]==0) { fprintf(stderr,"While exiting thread , thread_pool id[%u] is already zero.. This could be a bug ..\n",transaction->threadID); } instance->threads_pool[transaction->threadID]=0; ++instance->CLIENT_THREADS_STOPPED; //We also only want to stop the thread if itsnot prespawned ! //fprintf(stderr,"Exiting Thread\n"); //pthread_join(instance->threads_pool[transaction->threadID],0); //pthread_exit(0); //This should make the thread release all of its resources (?) pthread_detach(pthread_self()); } return 0; }
int ServeClientKeepAliveLoop(struct AmmServer_Instance * instance,struct HTTPTransaction * transaction) { //Remember the IP of this client.. getSocketIPAddress(instance,transaction->clientSock,transaction->ipStr,MAX_IP_STRING_SIZE,&transaction->port); //We have our connection / instancing /etc covered if we are here //In order to serve our client we must first receive the request header , so we do it now..! int httpHeaderReceivedWithNoProblems = receiveAndHandleHTTPHeaderSentByClient(instance,transaction); if (!httpHeaderReceivedWithNoProblems) { if (transaction->clientDisconnected) { warningID(ASV_WARNING_CONNECTION_CLOSED_WHILE_KEEPALIVE); } else { /*We got a bad http request so we will rig it to make server emmit the 400 message*/ errorID(ASV_ERROR_FAILED_TO_RECEIVE_HEADER); SendErrorFile(instance,transaction,400); logError(instance,transaction,400,"400.html"); } return 0; } else if (!clientList_isClientAllowedToUseResource(instance->clientList,transaction->clientListID,transaction->incomingHeader.resource)) { //Client is forbidden but he is not IP banned to use resource ( already opened too many connections or w/e other reason ) //Doesnt have access to the specific file , etc..! warningID(ASV_WARNING_CLIENT_DENIED_ACCESS); SendErrorCodeHeader(instance,transaction,403 ,"403.html",instance->templates_root); logError(instance,transaction,403,"403.html"); return 0; } else if ((instance->settings.PASSWORD_PROTECTION)&&(!transaction->incomingHeader.authorized)) { errorID(ASV_ERROR_UNAUTHORIZED_REQUEST); respondToClientRequestingAuthorization(instance,transaction); return 0; } else { // Not a Bad request Start //This is a hack and should be probably be changed..! if ( ( transaction->incomingHeader.requestType==POST ) && (instance->settings.ENABLE_POST) && (MASTER_ENABLE_POST) ) { fprintf(stderr,GREEN "POST HEADER : %lu length \n %s \n" NORMAL,transaction->incomingHeader.ContentLength,transaction->incomingHeader.headerRAW); //TODO ADD Here a possibly rfc1867 , HTTP POST FILE compatible (multipart/form-data) recv handler.. //TODO TODO TODO fprintf(stderr,"Found a POST query %lu bytes long , %s \n",transaction->incomingHeader.POSTrequestSize, transaction->incomingHeader.POSTrequest); warningID(ASV_WARNING_PRETENDING_IT_IS_A_GET_REQUEST); //Will now pretend that we are a GET request for the rest of the page to be served nicely transaction->incomingHeader.requestType=GET; } if ( (transaction->incomingHeader.requestType==GET) || (transaction->incomingHeader.requestType==HEAD) || (transaction->incomingHeader.requestType==POST) ) { char servefile[(MAX_FILE_PATH*2)+1]={0}; // Since we are strcat-ing the file on top of the webserver_root it is only logical to // reserve space for two MAX_FILE_PATHS they are a software security limitation ( system max_path is much larger ) so its not a problem anywhere..! int resource_is_a_directory=0,resource_is_a_file=0,resource_is_a_template=0,generate_directory_list=0; /*! PART 1 : Sense what we want to serve , and set the flags resource_is_a_directory , resource_is_a_file , generate_directory_list accordingly..! */ decideAboutHowToHandleRequestedResource ( instance, transaction, servefile, &resource_is_a_directory, &resource_is_a_file , &resource_is_a_template , &generate_directory_list ); /*! PART 2 : The flags resource_is_a_directory , resource_is_a_file , generate_directory_list have been set to the correct ( :P ) value so all we have to do now is serve the correct repsonse..! */ if (resource_is_a_template) { //We have a specific request for a file ( transaction->incomingHeader.resource ) fprintf(stderr,"It is a template request for %s ..!\n",servefile); // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ if ( SendEmbeddedFile ( instance, transaction, servefile // -- Log What was asked to be served ) ) { logSuccess(instance,transaction,200,servefile); } else { //We where unable to serve request , closing connections..\n errorID(ASV_ERROR_UNABLE_TO_SERVE_TEMPLATE); return 0; } // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ } else if (generate_directory_list) { respondToClientBySendingAGeneratedDirectoryList(instance,transaction,servefile); return 0; } else if (resource_is_a_file) { //We have a specific request for a file ( transaction->incomingHeader.resource ) //fprintf(stderr,"It is a file request for %s ..!\n",servefile); // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ if ( SendFile ( instance, transaction, servefile, // -- Log What was asked to be served 0 // <- We dont want to force an error code! ) ) { logSuccess(instance,transaction,200,servefile); } else { //We where unable to serve request , closing connections..\n errorID(ASV_ERROR_UNABLE_TO_SERVE_REQUEST); return 0; } // ------------------------------------------------------ // ------------------------------------------------------ // ------------------------------------------------------ } else { fprintf(stderr,"404 not found..!!\n"); SendErrorFile(instance,transaction,404); logError(instance,transaction,404,servefile); return 0; } } else if (transaction->incomingHeader.requestType==BAD) { //In case some of the security features of the server sensed a BAD! request we should log it.. warningID(ASV_WARNING_PREDATORY_REQUST); //TODO : call -> int ErrorLogAppend(char * IP,char * DateStr,char * Request,unsigned int ResponseCode,unsigned long ResponseLength,char * Location,char * Useragent) SendErrorFile(instance,transaction,400); logError(instance,transaction,400,"400.html"); return 0; } else if (transaction->incomingHeader.requestType==NONE) { //We couldnt find a request type so it is a weird input that doesn't seem to be HTTP based warningID(ASV_WARNING_UNRECOGNIZED_REQUEST); SendErrorFile(instance,transaction,400); logError(instance,transaction,400,"400.html"); return 0; } else { //The request we got requires not implemented functionality , so we will admit not implementing it..! :P warningID(ASV_WARNING_NOTIMPLEMENTED_REQUEST); SendErrorFile(instance,transaction,501); logError(instance,transaction,501,"501.html"); return 0; } } // Not a Bad request END clientList_signalClientStoppedUsingResource(instance->clientList,transaction->clientListID,transaction->incomingHeader.resource); // This in order for client_list to correctly track client behaviour..! if ( transaction->incomingHeader.headerRAW!=0 ) { safeFree(transaction->incomingHeader.headerRAW,transaction->incomingHeader.headerRAWSize); transaction->incomingHeader.headerRAW=0; } //We are done with request! if (!transaction->incomingHeader.keepalive) { return 0; } // Close_connection controls the receive "keep-alive" loop //If we are on a keepalive streak , then go on ! return 1; }
void RDSocket::errorData(int error) { emit errorID(error,id_num); }