void reply_404(char *item, int fd, struct logInformation *logInfo)
{
    char message[] = "Could not find the item you requested.";
    int bytes = httpReply(fd, NULL, 404, "Not Found", "text/plain", message, NULL, sizeof(message), logInfo);
    
    // update the bytes sent statistics
    updateBytesSent(bytes);
}
void reply_notImplemented(int fd, struct logInformation *logInfo)
{
    char message[] = "That command is not implemented on this system.";
    int bytes = httpReply(fd, NULL, 501, "Not Implemented", "text/plain", message, NULL, sizeof(message), logInfo);
    
    // update the bytes sent statistics
    updateBytesSent(bytes);
}
void reply_cat(char *fileName, int fd, struct logInformation *logInfo)
{
    const TIME_STRING_LENGTH = 30;
    char *type;
    char *extension = getFileNameExtension(fileName);
    FILE *fpSocket;
    FILE *fpLocal;
    int character;
    int bytes = 0;
    char timeString[TIME_STRING_LENGTH];
    
    if (strcmp(extension, "html") == 0)
        type = "text/html";
    else if (strcmp(extension, "gif") == 0)
        type = "image/gif";
    else if (strcmp(extension, "jpg") == 0)
        type = "image/jpeg";
    else if (strcmp(extension, "jpeg") == 0)
        type = "image/jpeg";
    else
        type = "text/plain";
        
    fpSocket = fdopen(fd, "w");
    fpLocal = fopen(fileName, "r");
    if (fpSocket != NULL && fpLocal != NULL)
    {
        // get the last modified time for the file
        struct stat info;
        stat(fileName, &info);
        strncpy(timeString, asctime(gmtime(&(info.st_mtime))), TIME_STRING_LENGTH - 1); // get the Greenwich Mean Time
        char *timeStringPointer = timeString;
        // step through the time string until we find the newline character and 
        // change it to a null character to remove it
        while (*timeStringPointer != '\n')
        {
            timeStringPointer++;
        }
        *timeStringPointer = '\0'; 
        // count the number of bytes that will be sent
        while ((character = getc(fpLocal)) != EOF)
        {
            bytes++;
        }         
        rewind(fpLocal);    
        bytes += httpReply(fd, &fpSocket, 200, "OK", type, NULL, timeString, bytes, logInfo);
        while ((character = getc(fpLocal)) != EOF)
        {
            putc(character, fpSocket);
        }
        fclose(fpSocket);
        fclose(fpLocal);
    }
    
    // update the bytes sent statistics    
    updateBytesSent(bytes);
}
void reply_status(int fd, struct logInformation *logInfo)
{
    FILE *fp;
    
    httpReply(fd, &fp, 200, "OK", "text/plain", NULL, NULL, 0, logInfo);
    
    pthread_mutex_lock(&statisticsLock);
    fprintf(fp, "Server started: %s", ctime(&timeServerStarted));
    fprintf(fp, "Total requests: %d\n", numberServerRequests);
    fprintf(fp, "Bytes sent out: %d\n\n", bytesSentFromServer);
    fclose(fp);
    pthread_mutex_unlock(&statisticsLock);
}
Beispiel #5
0
void RespondElement::enterElement(const Arabica::DOM::Element<std::string>& node) {
	// try to get the request id
	if (!HAS_ATTR(node, "to")) {
		LOG(ERROR) << "Respond element requires to attribute";
		return;
	}
	if (HAS_ATTR(node, "to") && !_interpreter->getDataModel()) {
		LOG(ERROR) << "Respond element with to requires datamodel";
		return;
	}
	std::string requestId = _interpreter->getDataModel().evalAsString(ATTR(node, "to"));

	// try to get the request object
	InterpreterHTTPServlet* servlet = _interpreter->getHTTPServlet();
	tthread::lock_guard<tthread::recursive_mutex> lock(servlet->getMutex());

	if (servlet->getRequests().find(requestId) == servlet->getRequests().end()) {
		LOG(ERROR) << "No matching HTTP request for respond element";
		return;
	}

	assert(servlet->getRequests().find(requestId) != servlet->getRequests().end());
	HTTPServer::Request httpReq = servlet->getRequests()[requestId];
	assert(httpReq.evhttpReq != NULL);
	HTTPServer::Reply httpReply(httpReq);
	servlet->getRequests().erase(requestId);

	// get the status or default to 200
	std::string statusStr = (HAS_ATTR(node, "status") ? ATTR(node, "status") : "200");
	if (!isNumeric(statusStr.c_str(), 10)) {
		LOG(ERROR) << "Respond element with non-numeric status " << statusStr;
		return;
	}
	httpReply.status = strTo<int>(statusStr);;

	// extract the content
	Arabica::XPath::NodeSet<std::string> contents = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "content", node);
	if (contents.size() > 0) {
		Arabica::DOM::Element<std::string> contentElem = Arabica::DOM::Element<std::string>(contents[0]);
		if (HAS_ATTR(contentElem, "expr")) { // -- content is evaluated string from datamodel ------
			if (_interpreter->getDataModel()) {
				try {
					Data contentData = _interpreter->getDataModel().getStringAsData(ATTR(contentElem, "expr"));
					if (contentData.atom.length() > 0) {
						httpReply.content = contentData.atom;
						httpReply.headers["Content-Type"] = "text/plain";
					} else if (contentData.binary) {
						httpReply.content = std::string(contentData.binary.getData(), contentData.binary.getSize());
						httpReply.headers["Content-Type"] = contentData.binary.getMimeType();
					} else if (contentData.node) {
						std::stringstream ss;
						ss << contentData.node;
						httpReply.content = ss.str();;
						httpReply.headers["Content-Type"] = "application/xml";
					} else {
						httpReply.content = Data::toJSON(contentData);
						httpReply.headers["Content-Type"] = "application/json";
					}
				} catch (Event e) {
					LOG(ERROR) << "Syntax error with expr in content child of Respond element:" << std::endl << e << std::endl;
					return;
				}
			} else {
				LOG(ERROR) << "content element has expr attribute but no datamodel is specified.";
				return;
			}
		} else if (HAS_ATTR(contentElem, "file") || HAS_ATTR(contentElem, "fileexpr")) { // -- content is from file ------
			URL file;
			if (HAS_ATTR(contentElem, "fileexpr")) {
				if (_interpreter->getDataModel()) {
					try {
						file = "file://" + _interpreter->getDataModel().evalAsString(ATTR(contentElem, "fileexpr"));
					} catch (Event e) {
						LOG(ERROR) << "Syntax error with fileexpr in content child of Respond element:" << std::endl << e << std::endl;
						return;
					}
				}
			} else {
				file = "file://" + ATTR(contentElem, "fileexpr");
			}
			if (file) {
				httpReply.content = file.getInContent();
				size_t lastDot;
				if ((lastDot = file.path().find_last_of(".")) != std::string::npos) {
					std::string extension = file.path().substr(lastDot + 1);
					std::string mimeType = URL::getMimeType(extension);
					if (mimeType.length() > 0) {
						httpReply.headers["Content-Type"] = mimeType;
					}
				}
			}
		} else if (contents[0].hasChildNodes()) {  // -- content embedded as child nodes ------
			httpReply.content = contents[0].getFirstChild().getNodeValue();
		} else {
			LOG(ERROR) << "content element does not specify any content.";
			return;
		}
	}

	// process headers
	Arabica::XPath::NodeSet<std::string> headers = InterpreterImpl::filterChildElements(_interpreter->getNameSpaceInfo().getXMLPrefixForNS(getNamespace()) + "header", node);
	for (int i = 0; i < headers.size(); i++) {
		Arabica::DOM::Element<std::string> headerElem = Arabica::DOM::Element<std::string>(headers[i]);

		std::string name;
		if (HAS_ATTR(headerElem, "name")) {
			name = ATTR(headerElem, "name");
		} else if(HAS_ATTR(headerElem, "nameexpr")) {
			if (_interpreter->getDataModel()) {
				try {
					name = _interpreter->getDataModel().evalAsString(ATTR(headerElem, "nameexpr"));
				} catch (Event e) {
					LOG(ERROR) << "Syntax error with nameexpr in header child of Respond element:" << std::endl << e << std::endl;
					return;
				}
			} else {
				LOG(ERROR) << "header element has nameexpr attribute but no datamodel is specified.";
				return;
			}
		} else {
			LOG(ERROR) << "header element has no name or nameexpr attribute.";
			return;
		}

		std::string value;
		if (HAS_ATTR(headerElem, "value")) {
			value = ATTR(headerElem, "value");
		} else if(HAS_ATTR(headerElem, "valueexpr")) {
			if (_interpreter->getDataModel()) {
				try {
					value = _interpreter->getDataModel().evalAsString(ATTR(headerElem, "valueexpr"));
				} catch (Event e) {
					LOG(ERROR) << "Syntax error with valueexpr in header child of Respond element:" << std::endl << e << std::endl;
					return;
				}
			} else {
				LOG(ERROR) << "header element has valueexpr attribute but no datamodel is specified.";
				return;
			}
		} else {
			LOG(ERROR) << "header element has no value or valueexpr attribute.";
			return;
		}

		httpReply.headers[name] = value;
	}

	// send the reply
	HTTPServer::reply(httpReply);
	servlet->getRequests().erase(requestId);
}
void reply_ls(char *directory, int fd, struct logInformation *logInfo)
{
    const TIME_STRING_LENGTH = 30;
    DIR *directoryPointer;
    struct dirent *direntPointer;
    FILE *fp;
    int bytes = 0;
    int numberEntries = 0;
    struct dirent **directoryEntryPointerArray;   
    char timeString[TIME_STRING_LENGTH]; 
    
    if ((directoryPointer = opendir(directory)) != NULL)
    {
        // count the number of bytes to be sent while simultaneously counting the number of entries
        while (direntPointer = readdir(directoryPointer))
        {
            char *pointer = direntPointer->d_name;
            if (*pointer != '.')
            {
                numberEntries++;
                while (*pointer != '\0')
                {
                    pointer++;
                    bytes++;
                }
            }
        }
        
        bytes += sizeof("Listing directory") + sizeof(directory); // count bytes in beginning of response too
        
        rewinddir(directoryPointer);

        // allocate memory for an array to hold the directory entries. We will need this for sorting and arrangining into columns
        // MENTAL CHECK: Is the memory set free later? --> YES
        directoryEntryPointerArray = malloc(numberEntries * sizeof(struct dirent *));
        
        // populate the directory entry pointer array
        int i = 0;
        while (direntPointer = readdir(directoryPointer))
        {
          if (*(direntPointer->d_name) != '.')
          {
            directoryEntryPointerArray[i] = direntPointer;
            i++;
          }
        }   
                 
        // sort the directory entry pointer array
        sortDirectoryEntries(numberEntries, directoryEntryPointerArray);         
    
        // get the last modified time for the directory
        struct stat info;
        stat(directory, &info);
        strncpy(timeString, asctime(gmtime(&(info.st_mtime))), TIME_STRING_LENGTH - 1); // get the Greenwich Mean Time
        char *timeStringPointer = timeString;
        // step through the time string until we find the newline character and 
        // change it to a null character to remove it
        while (*timeStringPointer != '\n')
        {
            timeStringPointer++;
        }
        *timeStringPointer = '\0';     
    
        // send the http status code and header
        bytes += httpReply(fd, &fp, 200, "OK", "text/plain", NULL, timeString, bytes, logInfo);
        bytes += fprintf(fp, "Listing directory %s\n", directory);
        
        // print the directory entries
        for (i = 0; i < numberEntries; i++)
        {
            fprintf(fp, "%s\n", directoryEntryPointerArray[i]->d_name);
        } 
        
        closedir(directoryPointer);
    }        
    
    // close the file pointer
    fclose(fp);  
    
    // update the bytes sent statistics
    updateBytesSent(bytes);
    
    // free memory
    free(directoryEntryPointerArray);
}
void reply_cgi(char *program, int fd, struct logInformation *logInfo)
{
    int bytes = 0;
    int thePipe[2];
    int originalStandardInput;
    FILE *fpInput;
    FILE *fpOutput;
    int character;
    int *buffer;
    
    if (pipe(thePipe) == -1)
    {
        perror("Could not make a pipe!\n");
        return;
    }    
    int pid = fork();
    switch (pid)
    {
        case -1: 
            perror(program);
            break;
        case 0:    // child process
            close(thePipe[0]);
            if (dup2(thePipe[1], 1) == -1)
            {
                perror("Could not redirect stdout");
                exit(1);
            }
            char *path = malloc(strlen(rootDirectory) + strlen(CGI_PATH) + strlen(program) + 1);
            strcpy(path, rootDirectory);
            strcat(path, CGI_PATH);
            strcat(path, program);
            //printf("cgi search path = %s\n", path);
            execl(path, program, NULL);
            perror(program);
            free(path);
            exit(1);
            break;
        default: // parent process
            //printf("Pipe reading fd = %d\nPipe writing fd = %d\n", thePipe[0], thePipe[1]);
            close(thePipe[1]);
            originalStandardInput = dup(0);
            if (dup2(thePipe[0], 0) == -1)
            {
                perror("Could not redirect stdin");
                break;
            }
            close(thePipe[0]);
            wait(NULL);
            
            fpInput = fdopen(0, "r");
            // read from the pipe
            // count the number of bytes that will be sent
            if (fpInput)
            {
                // we are going to need to save what we read from the pipe because we will 
                // not be able to read it again. Allocate an initial buffer and increase it 
                // everytime we need to add something 
                buffer = malloc(sizeof(int)); 
                int i = 0;
                while ((character = getc(fpInput)) != EOF)
                {
                    buffer[i] = character;
                    i++;
                    buffer = realloc(buffer, (i+1) * sizeof(int));
                    bytes++;
                }     
                // allocate an EOF character to the end of the buffer   
                buffer = realloc(buffer, (i+1) * sizeof(int));
                buffer[i] = EOF;  
                bytes += httpReply(fd, &fpOutput, 200, "OK", "text/plain", NULL, NULL, bytes, logInfo);
                if (fpOutput)
                {
                    i = 0;
                    while (buffer[i] != EOF)
                    {
                        putc(buffer[i], fpOutput);
                        i++;
                    }            
                    fclose(fpOutput);
                }
                fclose(fpInput);
            }

            
            // reset stdin to original file descriptor
            if (dup2(originalStandardInput, 0) == -1)
                perror("Could not reset stdin to original file descriptor");
            
            // update the bytes sent statistics
            updateBytesSent(bytes); 
    } 
}