Esempio n. 1
0
// Processes a single request from a web client.
void webserver_process_request (int connfd, string clientaddress)
{
  mutex_requests.lock ();
  config_globals_simultaneous_connection_count++;
  mutex_requests.unlock ();

  // The environment for this request.
  // It gets passed around from function to function during the entire request.
  // This provides thread-safety to the request.
  Webserver_Request request;

  // Store remote client address in the request.
  request.remote_address = clientaddress;
  
  try {
    if (config_globals_running) {
      
      // Connection health flag.
      bool connection_healthy = true;
      
      // Read the client's request.
      // With the HTTP protocol it is not possible to read the request till EOF,
      // because EOF does never come, because the browser keeps the connection open
      // for the response.
      // The HTTP protocol works per line.
      // Read one line of data from the client.
      // An empty line marks the end of the headers.
#define BUFFERSIZE 2048
      int bytes_read;
      bool header_parsed = true;
      char buffer [BUFFERSIZE];
      // Fix valgrind unitialized value message.
      memset (&buffer, 0, BUFFERSIZE);
      do {
        bytes_read = get_line (connfd, buffer, BUFFERSIZE);
        if (bytes_read <= 0) connection_healthy = false;
        // Parse the browser's request's headers.
        header_parsed = http_parse_header (buffer, &request);
      } while (header_parsed);
      
      if (connection_healthy) {
        
        // In the case of a POST request, more data follows: The POST request itself.
        // The length of that data is indicated in the header's Content-Length line.
        // Read that data, and parse it.
        string postdata;
        if (request.is_post) {
          bool done_reading = false;
          int total_bytes_read = 0;
          do {
            bytes_read = read (connfd, buffer, BUFFERSIZE);
            for (int i = 0; i < bytes_read; i++) {
              postdata += buffer [i];
            }
            // EOF indicates reading is ready.
            // An error also indicates that reading is ready.
            if (bytes_read <= 0) done_reading = true;
            if (bytes_read < 0) connection_healthy = false;
            // "Content-Length" bytes read: Done.
            total_bytes_read += bytes_read;
            if (total_bytes_read >= request.content_length) done_reading = true;
          } while (!done_reading);
          if (total_bytes_read < request.content_length) connection_healthy = false;
        }
        
        if (connection_healthy) {

          http_parse_post (postdata, &request);
          
          // Assemble response.
          bootstrap_index (&request);
          http_assemble_response (&request);
          
          // Send response to browser.
          const char * output = request.reply.c_str();
          // The C function strlen () fails on null characters in the reply, so take string::size()
          size_t length = request.reply.size ();
          int written = write (connfd, output, length);
          if (written) {};
          
        } else {
          // cerr << "Insufficient data received, closing connection" << endl;
        }

      } else {
        // cerr << "Unhealthy connection was closed" << endl;
      }
    }
  } catch (exception & e) {
    string message ("Internal error: ");
    message.append (e.what ());
    Database_Logs::log (message);
  } catch (exception * e) {
    string message ("Internal error: ");
    message.append (e->what ());
    Database_Logs::log (message);
  } catch (...) {
    Database_Logs::log ("A general internal error occurred");
  }
  
  // Done: Close.
  close (connfd);

  mutex_requests.lock ();
  config_globals_simultaneous_connection_count--;
  mutex_requests.unlock ();
}
Esempio n. 2
0
/*------------------------------------------------------------------------
 * The received header must contain the word "GET" or "POST" to be 
 * considered a valid request.
 * With HTTP 1.1 where the connection is left open, the header I send
 * should include content length. With HTTP 1.0 you can just close the
 * connection after sending the page and the browser knows its done. 
 *
 * The HTTP protocol specification is at http://www.w3.org/Protocols/ 
 *------------------------------------------------------------------------
 */
ushort http_server(uchar *inbuf, ushort header_len, ushort tcp_len,
		   uchar nr, uchar resend)
{
	static uint	counter=0;
	uint	content_length;
	uint	data_len;
	uchar 	*ptr;
	uchar 	*tcp_data;

	if (http_debug == DEBUG)
		printf("\n\n%s************ tcp_len = %d ************%d\n",
			__func__,tcp_len,http_state);
	else
		if ((counter++ % 100) == 0)
			printf(".");
		    	
	/* Make sure this is a valid connection */
	if (nr == NO_CONNECTION) 
		return 0;
	
	/* Compute start of TCP data */
	
	/* Save first 20 chars and seq number just in case
	 * we need to re-generate page
	 * TODO: if post, then save switch state infomation
	 * If this is a resend, set sequence number to what it was
	 * the last time we sent this
	 */
	if (!resend) {
		tcp_data = inbuf + ETHER_IP_HLEN + header_len;
		memcpy(conxn[nr].query, tcp_data, 20);
		conxn[nr].old_sequence = conxn[nr].my_sequence;
	} else {
		tcp_data = inbuf;
		conxn[nr].my_sequence = conxn[nr].old_sequence;   
	}

	if (http_debug == DEBUG)
		printf("#1> http_state = %d......\n",http_state);

	/* Pre-porcess HTTP state change. */
	switch (http_state) {
	case HTTP_START:
		if ( (strstr((const char *)tcp_data, "GET") != NULL) && 
		     ((strstr((const char *)tcp_data, "index") != NULL) || 
		      (strstr((const char *)tcp_data, "/ ") != NULL)) )
			http_state = HTTP_GET;
		else if ( (strstr((const char *)tcp_data, "POST") != NULL) )
			http_state = HTTP_POST;
		break;

	case HTTP_GET:
		if ( (strstr((const char *)tcp_data, "POST") != NULL) )
			http_state = HTTP_POST;
		break;
		
	case HTTP_UPLOAD:  /* process the situation of network disconnection */
		if ( (strstr((const char *)tcp_data, "GET") != NULL) && 
		     ((strstr((const char *)tcp_data, "index") != NULL) || 
		      (strstr((const char *)tcp_data, "/ ") != NULL)) )
			http_state = HTTP_GET;
		break;
	}
	
	switch (http_state) {
	case HTTP_START:
		break;
		
	case HTTP_GET:
	      	/* send download page to HTTP client */
		http_send_ok(nr, web_page, 200, "OK");
		break;

	case HTTP_POST:
		if (http_parse_post(tcp_data, &content_length)) {
			http_state = HTTP_START;
			return 1;
		} else {
			post_info.upload_len = content_length;
			post_info.data_len = 0;
			post_info.buf = (uchar *)upgrade_buffer;
			http_state = HTTP_HEAD_DATA;
		}

		if (http_parse_mime(tcp_data, tcp_len - header_len, nr) == 0)
			http_state = HTTP_UPLOAD;
		break;

	case HTTP_HEAD_DATA:
		post_info.rcv_len = tcp_len - header_len;

		if (http_check_filename(tcp_data)) {
			http_send_error(nr, 400, "Bad Request",
				"No upload file name to be slected !");
			http_state = HTTP_START;
			return 1;			
		}
		
		ptr = (uchar *)strstr((const char *)tcp_data, c_headerend);
		ptr = ptr + strlen(c_headerend); /* upload file start pointer */
		
		data_len = tcp_len - header_len - (ptr - tcp_data );
		post_info.data_len = data_len;
		memcpy(post_info.buf, ptr, data_len);

		http_state = HTTP_UPLOAD;
		break;

	case HTTP_UPLOAD:
		post_info.rcv_len += tcp_len - header_len;

		if (http_debug == DEBUG) {
			printf("post_info.rcv_len=%d  post_info.upload_len=%d\n"
				,post_info.rcv_len,post_info.upload_len);
		}
		
		if (post_info.rcv_len >= post_info.upload_len) {
			/* To check the last packet if contains image data. */
			/* 6-byte include two "--" and one \r\n */
			/* 8-byte include two "--" and two \r\n */
			if ((tcp_len - header_len) > (strlen(boundary_code)+6)) 
				data_len = tcp_len - header_len - \
						strlen(boundary_code) - 8;
			else
				data_len = 0;

			if (http_check_image(post_info.buf, post_info.data_len)) {
				http_send_error(nr, 400, "Bad Request",
						 "File format is invalid !");
				http_state = HTTP_START;
				return (1);
			} else {			
				memset(text, 0x00, sizeof(text));
#ifdef CONFIG_MTD_CORTINA_CS752X_NAND
				sprintf(text,"%d", 5 + post_info.data_len/(1024*1000));
#else
				sprintf(text,"%d", 10 + post_info.data_len/(1024*100));
#endif
				replace_tag((uchar *)upgrade200_1, "TAG:NUM1", text);
	
				http_send_ok(nr, upgrade200_1, 200, "OK");	

				if (do_upgrade_image(post_info.buf, post_info.data_len)) {
					http_state = HTTP_START;
					return 0;
				} else {
					http_state = HTTP_REBOOT;
					break;
				}
			}

		} else {
			data_len = tcp_len - header_len;
			memcpy((void *)&post_info.buf[post_info.data_len], tcp_data, data_len);
			post_info.data_len += data_len;
		}
			
		break;

	case HTTP_REBOOT:
		if ( (strstr((const char *)tcp_data, "GET") != NULL) && 
		     (strstr((const char *)tcp_data, "reboot") != NULL) ) {    	
			http_state = HTTP_START;
			http_send_ok(nr, reboot200, 200, "OK");
			/* 
			 * Reserved time for tx those packets that queue 
			 * in packet buffer before system reset.
			 */
			udelay(500);
			do_reset(NULL, 0, 0, NULL);
		}
		break;

	default:
		printf("HTTP State Error ! %d\n", http_state);
		break;
	}

	if (http_debug == DEBUG)
		printf("#2> http_state = %d......\n",http_state);
	
	return 0;
}