/** * The main function that handles an HTTP request. */ int main(int argc, const char *argv[]) { req_t *req; if (argc < 2) { return -1; } document_root = argv[1]; req = read_request(0); if (!req && errno != 0) { // internal error perror("httpd"); send_error(stdout, 500, "Internal Server Error", "Internal server error: %s", strerror(errno)); return 1; } else if (!req || !req_is_valid(req)) { send_error(stdout, 400, "Bad Request", "Incomplete or invalid request."); return 0; } else { if (handle_request(req, stdout) < 0) { return 1; } else { return 0; } } }
int srv_handle_req(srv_t *srv) { base_req_t *req = (base_req_t *)srv->req; if(!req_is_valid(req)) return (srv->fn_rv = RRW_RV_BAD_REQ); switch(req->fn) { case RRW_FN_STATUS: srv->fn_rv = srv_handle_status_req(srv); break; case RRW_FN_MEAS_CTL: srv->fn_rv = srv_handle_meas_ctl_req(srv); break; case RRW_FN_TEST: srv->fn_rv = srv_handle_test_req(srv); break; case RRW_FN_DATA: srv->fn_rv = srv_handle_data_req(srv); break; default: srv->fn_rv = RRW_RV_BAD_REQ; break; } return srv->fn_rv; }
/**Handle request in dependence of its type*/ int srv_handle_req(srv_t *srv) { base_req_t *req = (base_req_t *)srv->req; //if request has no validity mark stop further processing if(!req_is_valid(req)) { #ifdef DBG_SRV logprintf("SERVER: invalid request!\n"); #endif // DBG_SRV return (srv->fn_rv = RRW_RV_BAD_REQ); } //call appropriate handler and set request return value (srv->fn_rv) switch(req->fn) { case RRW_FN_STATUS: #ifdef DBG_SRV logprintf("SERVER: %d get status!\n",((base_req_t *)srv->req)->no); #endif srv->fn_rv = srv_handle_status_req(srv); break; case RRW_FN_MEAS_CTL: #ifdef DBG_SRV logprintf("SERVER: %d measurement control!\n",((base_req_t *)srv->req)->no); #endif srv->fn_rv = srv_handle_meas_ctl_req(srv); break; case RRW_FN_DATA_ALT: #ifdef DBG_SRV if(req->fn == RRW_FN_DATA) logprintf("SERVER: %d get data!\n",((base_req_t *)srv->req)->no); if(req->fn == RRW_FN_DATA_ALT) logprintf("SERVER: %d get data alt!\n",((base_req_t *)srv->req)->no); #endif srv->fn_rv = srv_handle_data_req(srv); break; case RRW_FN_SET_TH: #ifdef DBG_SRV logprintf("SERVER: %d set threshold!\n",((base_req_t *)srv->req)->no); #endif srv->fn_rv = srv_handle_setth_req(srv); break; case RRW_FN_GET_TH: #ifdef DBG_SRV logprintf("SERVER: %d get threshold!\n",((base_req_t *)srv->req)->no); #endif srv->fn_rv = srv_handle_getth_req(srv); break; default: #ifdef DBG_SRV logprintf("SERVER: %d incorrect function code!\n",((base_req_t *)srv->req)->no); #endif //if request contains incorrect function code process it as bad request srv->fn_rv = RRW_RV_BAD_REQ; break; } return srv->fn_rv; }
/** * Handle an HTTP request and produce an appropriate response. * * @param req The parsed HTTP request. * @param stream The stream to which the response should be printed. */ static int handle_request(req_t *req, FILE *stream) { g_return_val_if_fail(req != NULL, -1); g_return_val_if_fail(req_is_complete(req), -1); g_return_val_if_fail(req_is_valid(req), -1); g_return_val_if_fail(document_root != NULL, -1); const char *path = req_path(req); // check path validity if (strstr(path, "..")) { // oops, contains '..' send_error(stream, 400, "Bad Request", "Request path is invalid"); return 0; } else if (*path != '/') { // oops, is not absolute (no leading '/') send_error(stream, 400, "Bad Request", "Request path is invalid"); return 0; } int result = 0; // combine path with document root to get a UNIX file path char *filepath = g_build_filename(document_root, path, NULL); // now start examining it struct stat sb; if (stat(filepath, &sb) < 0) { // there is an error with the file switch (errno) { case ENOENT: send_error(stream, 404, "Not Found", "The resource %s could not be found.", path); break; case EACCES: send_error(stream, 401, "Forbidden", "The resource %s could not be read.", path); break; default: send_error(stream, 500, "Internal Server Error", "%s: %s", path, strerror(errno)); result = -1; break; } } else if (S_ISDIR(sb.st_mode)) { if (filepath[strlen(filepath) - 1] == '/') { // we have a directory with a proper path. check for index.html. char *ind_fp = g_build_filename(filepath, "index.html", NULL); if (stat(ind_fp, &sb) < 0) { // not found result = send_dir_index(stream, req, filepath); } else { // index.html exists result = send_file(stream, req, ind_fp, &sb); } g_free(ind_fp); } else { // no trailing '/', send a redirect fprintf(stream, "HTTP/1.0 301 Moved Permanently\r\n"); const char *host = req_host(req); if (host) { fprintf(stream, "Location: http://%s%s/\r\n", req_host(req), path); } else { // not entirely conformant, but the best we can do fprintf(stderr, "warning: no host in request\n"); fprintf(stream, "Location: %s/\r\n", path); } fprintf(stream, "\r\n"); } } else if (S_ISREG(sb.st_mode)) { result = send_file(stream, req, filepath, &sb); } else { send_error(stream, 401, "Forbidden", "Access denied."); } g_free(filepath); return result; }
/** * The main function that handles an HTTP request. */ int main(int argc, char **argv) { //obtain arguments int code; char *host = "::"; char *port = "4080"; char act_host[NI_MAXHOST]; char act_port[NI_MAXSERV]; //ssize_t result; //size_t bytes_done, req_len; struct sockaddr *addr; ssize_t addr_len; char **prog_args; FILE *handler; setup_signals(); while((code = getopt(argc, argv, "h:p:"))>0) { switch(code){ case 'h': host = optarg; break; case 'p': port = optarg; break; case '?': default: fprintf(stderr, "bad argument\n"); exit(EX_USAGE); } } prog_args = malloc((argc - optind + 1) * sizeof(char*)); for (int i = 0; i < argc - optind; i++) { prog_args[i] = argv[optind + i]; } prog_args[argc-optind] = NULL; addr_len = lookup_address(host, port, &addr); if (addr_len < 0) { fprintf(stderr, "%s:%s: %s\n", host, port, gai_strerror(addr_len)); exit(EXIT_FAILURE); } getnameinfo(addr, addr_len, act_host, NI_MAXHOST, act_port, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV); fprintf(stderr, "listening on %s:%s\n", act_host, act_port); int sock = socket(AF_INET6, SOCK_STREAM, 0); if (sock < 0) { perror("socket"); exit(EXIT_FAILURE); } code = bind(sock, addr, addr_len); if (code < 0) { perror("bind"); exit(EXIT_FAILURE); } code = listen(sock, 5); if (code < 0) { perror("listen"); exit(EXIT_FAILURE); } pid_t group = setpgrp(); // fprintf(stderr, "process group %d\n", group); //wait for connection and then process the request. while(keep_running){ fprintf(stderr, "waiting for connection \n"); struct sockaddr_in6 c_addr; socklen_t c_addr_len = sizeof(struct sockaddr_in6); int client = accept(sock, (void*) &c_addr, &c_addr_len); if(client < 0){ if(errno == EINTR){ continue; }else{ perror("accept"); exit(EXIT_FAILURE); } } pid_t child = fork(); if(child < 0){ perror("fork"); exit(EX_OSERR); }else if(child){ close(client); }else{ //close(sock); req_t *req; document_root = argv[optind]; req = read_request(client); handler = fdopen(client, "r+"); if (!req && errno != 0) { // internal error perror("httpd"); send_error(handler, 500, "Internal Server Error", "Internal server error: %s", strerror(errno)); return 1; } else if (!req || !req_is_valid(req)) { send_error(handler, 400, "Bad Request", "Incomplete or invalid request."); return 0; } else { //handler = fdopen(client, "r+"); if (handle_request(req, handler) < 0) { return 1; } else { fclose(handler); close(client); free(addr); return 0; } } close(sock); close(client); fclose(handler); } } close(sock); free(addr); return 0; }