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); }
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); } }