/* $begin proxy */ void proxy(int fd) { char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char buf_internet[MAXLINE], payload[MAX_OBJECT_SIZE]; char host[MAXLINE], path[MAXLINE]; int port, fd_internet; int found = 0; size_t n; size_t sum = 0; mio_t mio_user, mio_internet; cnode_t * node; /* Read request line and headers */ Mio_readinitb(&mio_user, fd); Mio_readlineb(&mio_user, buf, MAXLINE); printf("Request: %s\n", buf); if (strcmp(buf, "") == 0) return; sscanf(buf, "%s %s %s", method, uri, version); if (strcasecmp(method, "GET")) { clienterror(fd, method, "501", "Not Implemented", "Ming does not implement this method"); return; } read_requesthdrs(&mio_user); /* Parse URI from GET request */ if (!parse_uri(uri, host, &port, path)) { clienterror(fd, uri, "404", "Not found", "Ming couldn't parse the request"); return; } printf("uri = \"%s\"\n", uri); if (VERBOSE) { printf("host = \"%s\", ", host); printf("port = \"%d\", ", port); printf("path = \"%s\"\n", path); } if (CACHE_ENABLE) { /* Critcal readcnt section begin */ P(&mutex); readcnt++; if (readcnt == 1) // First in P(&w); V(&mutex); /* Critcal readcnt section end */ /* Critcal reading section begin */ Cache_check(); if ((node = match(host, port, path)) != NULL) { printf("Cache hit!\n"); delete(node); enqueue(node); Mio_writen(fd, node->payload, node->size); printf("Senting respond %u bytes from cache\n", (unsigned int)node->size); //fprintf(stdout, node->payload); found = 1; } /* Critcal reading section end */ /* Critcal readcnt section begin */ P(&mutex); readcnt--; if (readcnt == 0) V(&w); V(&mutex); /* Critcal readcnt section end */ if (found == 1) { printf("Proxy is exiting\n\n"); return; } printf("Cache miss!\n"); } fd_internet = Open_clientfd_r(host, port); Mio_readinitb(&mio_internet, fd_internet); /* Forward request */ sprintf(buf_internet, "GET %s HTTP/1.0\r\n", path); Mio_writen(fd_internet, buf_internet, strlen(buf_internet)); sprintf(buf_internet, "Host: %s\r\n", host); Mio_writen(fd_internet, buf_internet, strlen(buf_internet)); Mio_writen(fd_internet, user_agent_hdr, strlen(user_agent_hdr)); Mio_writen(fd_internet, accept_hdr, strlen(accept_hdr)); Mio_writen(fd_internet, accept_encoding_hdr, strlen(accept_encoding_hdr)); Mio_writen(fd_internet, connection_hdr, strlen(connection_hdr)); Mio_writen(fd_internet, pxy_connection_hdr, strlen(pxy_connection_hdr)); /* Forward respond */ strcpy(payload, ""); while ((n = Mio_readlineb(&mio_internet, buf_internet, MAXLINE)) != 0) { //printf("Fd = %d, Sum = %d, n = %d\n", mio_internet.mio_fd, sum, n); sum += n; if (sum <= MAX_OBJECT_SIZE) strcat(payload, buf_internet); Mio_writen(fd, buf_internet, n); } printf("Forward respond %d bytes\n", sum); if (CACHE_ENABLE) { if (sum <= MAX_OBJECT_SIZE) { node = new(host, port, path, payload, sum); /* Critcal write section begin */ P(&w); Cache_check(); while (cache_load + sum > MAX_CACHE_SIZE) { printf("!!!!!!!!!!!!!!!!!Cache evicted!!!!!!!!!!!!!!!!!!\n"); dequeue(); } enqueue(node); printf("The object has been cached\n"); printf("Current cache size is %d \n", cache_count); printf("Current cache load is %d bytes\n", cache_load); //fprintf(stdout, payload); Cache_check(); V(&w); /* Critcal write section end */ } }
void doit(int fd) { char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE]; char hostname[MAXLINE], path[MAXLINE], port[MAXLINE]; char host_header[MAXLINE], remaining_headers[MAXLINE]; char request[MAXLINE], server_buf[MAXLINE]; rio_t rio; rio_t server_rio; memset(buf, 0, MAXLINE); memset(method, 0, MAXLINE); memset(uri, 0, MAXLINE); memset(version, 0, MAXLINE); memset(hostname, 0, MAXLINE); memset(path, 0, MAXLINE); memset(port, 0, MAXLINE); memset(host_header, 0, MAXLINE); memset(remaining_headers, 0, MAXLINE); memset(request, 0, MAXLINE); memset(server_buf, 0, MAXLINE); /* Read request line and headers */ Rio_readinitb(&rio, fd); Rio_readlineb(&rio, buf, MAXLINE); sscanf(buf, "%s %s %s", method, uri, version); if (strcasecmp(method, "GET")) { clienterror(fd, method, "501", "Not Implemented", "Tiny does not implement this method"); return; } cache_node *cache_hit = check_for_hit(proxy_cache, uri); if (cache_hit != NULL){ if(rio_writen(fd, cache_hit->data, cache_hit->data_size) < 0){ pthread_rwlock_unlock(&lock); return; } } pthread_rwlock_unlock(&lock); if (cache_hit == NULL) { char *response_data = Malloc(sizeof(char)); unsigned int data_size = 0; read_requesthdrs(&rio, host_header, remaining_headers); /* Parse URI from GET request */ if (parse_uri(uri, hostname, path, port) < 0) { return; } if (strncmp(host_header, "Host: ", strlen("Host: ")) != 0){ sprintf(host_header, "Host: %s\r\n", hostname); } // printf("%s %s %s\n", hostname, path, port); compile_request(request, host_header, path, remaining_headers); int port_num = atoi(port); int server_fd = Open_clientfd_r(hostname, port_num); if (rio_writen(server_fd, request, strlen(request)) < 0){ return; } Rio_readinitb(&server_rio, server_fd); int len; while ((len = rio_readnb(&server_rio, server_buf, MAXLINE)) > 0){ if (rio_writen(fd, server_buf, len) < 0){ return; } response_data = Realloc(response_data, data_size + len); memcpy(response_data + data_size, server_buf, len); data_size += len; } add_to_cache(proxy_cache, uri, response_data, data_size); Close(server_fd); Free(response_data); return; } }
/* Takes a request and forwards it to its destination server by opening a client * connection. Returns the response of the destination server. * This function frees memory allocated for the request also using free_req() */ void forward_request(int fd, req_t request){ int server; size_t n, total_read; cache_obj* entry; char *name, *portstr, http[1024], buf[MAXLINE], cachebuf[MAX_OBJECT_SIZE]; rio_t rio; cachebuf[0] = '\0'; name = strtok(request.domain, ":"); portstr = strtok(NULL, ":"); if(name == NULL){ free_req(request); return; } if(portstr == NULL) portstr = "80"; // checking the cache is still updating it (age) P(&w); if((entry = in_cache(request.path, num_entries, cache)) != NULL){ V(&w); Rio_writen(fd, entry->buf, entry->obj_size); } else { V(&w); server = Open_clientfd_r(name, atoi(portstr)); if(server != -1){ sprintf(http, "GET /%s HTTP/1.0\r\n", request.path); strcat(http, request.hdrs); Rio_writen(server, http, strlen(http)); Rio_writen(server, "\r\n", 2); } else { reparse(&request); char *wdpath; wdpath = getcwd(NULL,0); wdpath = Realloc(wdpath, strlen(wdpath) + strlen(request.path) +1); strcat(wdpath, request.path); server = open(wdpath, O_RDONLY); Free(wdpath); if(server == -1){ not_found(fd); free_req(request); return; } } Rio_readinitb(&rio, server); total_read = 0; while((n = Rio_readlineb(&rio, buf, MAXLINE)) > 0){ if(total_read+n <= MAX_OBJECT_SIZE){ strcat(cachebuf, buf); } total_read += n; Rio_writen(fd, buf, n); } // cache update, critical section if(total_read <= MAX_OBJECT_SIZE){ P(&w); cache = cache_write(request.path, cachebuf, num_entries, cache); num_entries++; V(&w); } } free_req(request); }