204 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
             LUFA Library
 | 
						|
     Copyright (C) Dean Camera, 2017.
 | 
						|
 | 
						|
  dean [at] fourwalledcubicle [dot] com
 | 
						|
           www.lufa-lib.org
 | 
						|
*/
 | 
						|
 | 
						|
/*
 | 
						|
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)
 | 
						|
 | 
						|
  Permission to use, copy, modify, distribute, and sell this
 | 
						|
  software and its documentation for any purpose is hereby granted
 | 
						|
  without fee, provided that the above copyright notice appear in
 | 
						|
  all copies and that both that the copyright notice and this
 | 
						|
  permission notice and warranty disclaimer appear in supporting
 | 
						|
  documentation, and that the name of the author not be used in
 | 
						|
  advertising or publicity pertaining to distribution of the
 | 
						|
  software without specific, written prior permission.
 | 
						|
 | 
						|
  The author disclaims all warranties with regard to this
 | 
						|
  software, including all implied warranties of merchantability
 | 
						|
  and fitness.  In no event shall the author be liable for any
 | 
						|
  special, indirect or consequential damages or any damages
 | 
						|
  whatsoever resulting from loss of use, data or profits, whether
 | 
						|
  in an action of contract, negligence or other tortious action,
 | 
						|
  arising out of or in connection with the use or performance of
 | 
						|
  this software.
 | 
						|
*/
 | 
						|
 | 
						|
/** \file
 | 
						|
 *
 | 
						|
 *  Simple webserver application for demonstrating the RNDIS demo and TCP/IP stack. This
 | 
						|
 *  application will serve up a static HTTP web page when requested by the host.
 | 
						|
 */
 | 
						|
 | 
						|
#include "Webserver.h"
 | 
						|
 | 
						|
/** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the
 | 
						|
 *  given location, and gives extra connection information.
 | 
						|
 */
 | 
						|
const char HTTP200Header[] PROGMEM = "HTTP/1.1 200 OK\r\n"
 | 
						|
                                     "Server: LUFA RNDIS\r\n"
 | 
						|
                                     "Content-type: text/html\r\n"
 | 
						|
                                     "Connection: close\r\n\r\n";
 | 
						|
 | 
						|
/** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given
 | 
						|
 *  given URL is invalid, and gives extra error information.
 | 
						|
 */
 | 
						|
const char HTTP404Header[] PROGMEM = "HTTP/1.1 404 Not Found\r\n"
 | 
						|
                                     "Server: LUFA RNDIS\r\n"
 | 
						|
                                     "Connection: close\r\n\r\n";
 | 
						|
 | 
						|
/** HTTP page to serve to the host when a HTTP request is made. This page is too long for a single response, thus it is automatically
 | 
						|
 *  broken up into smaller blocks and sent as a series of packets each time the webserver application callback is run.
 | 
						|
 */
 | 
						|
const char HTTPPage[] PROGMEM =
 | 
						|
		"<html>"
 | 
						|
		"	<head>"
 | 
						|
		"		<title>"
 | 
						|
		"			LUFA Webserver Demo"
 | 
						|
		"		</title>"
 | 
						|
		"	</head>"
 | 
						|
		"	<body>"
 | 
						|
		"		<h1>Hello from your USB AVR!</h1>"
 | 
						|
		"		<p>"
 | 
						|
		"			Hello! Welcome to the LUFA RNDIS Demo Webserver test page, running on your USB AVR via the LUFA library. This demonstrates the HTTP webserver, TCP/IP stack and RNDIS demo all running atop the LUFA USB stack."
 | 
						|
		"			<br /><br />"
 | 
						|
		"			<small>Project Information: <a href=\"http://www.lufa-lib.org\">http://www.lufa-lib.org</a>.</small>"
 | 
						|
		"			<hr />"
 | 
						|
		"			<i>LUFA Version: </i>" LUFA_VERSION_STRING
 | 
						|
		"		</p>"
 | 
						|
		"	</body>"
 | 
						|
		"</html>";
 | 
						|
 | 
						|
 | 
						|
/** Initializes the Webserver application, opening the appropriate HTTP port in the TCP handler and registering the application
 | 
						|
 *  callback routine for packets sent to the HTTP protocol port.
 | 
						|
 */
 | 
						|
void Webserver_Init(void)
 | 
						|
{
 | 
						|
	/* Open the HTTP port in the TCP protocol so that HTTP connections to the device can be established */
 | 
						|
	TCP_SetPortState(TCP_PORT_HTTP, TCP_Port_Open, Webserver_ApplicationCallback);
 | 
						|
}
 | 
						|
 | 
						|
/** Indicates if a given request equals the given HTTP command.
 | 
						|
 *
 | 
						|
 *  \param[in] RequestHeader  HTTP request made by the host
 | 
						|
 *  \param[in] Command        HTTP command to compare the request to
 | 
						|
 *
 | 
						|
 *  \return Boolean \c true if the command matches the request, \c false otherwise
 | 
						|
 */
 | 
						|
static bool IsHTTPCommand(uint8_t* RequestHeader,
 | 
						|
                          char* Command)
 | 
						|
{
 | 
						|
	/* Returns true if the non null terminated string in RequestHeader matches the null terminated string Command */
 | 
						|
	return (strncmp((char*)RequestHeader, Command, strlen(Command)) == 0);
 | 
						|
}
 | 
						|
 | 
						|
/** Application callback routine, executed each time the TCP processing task runs. This callback determines what request
 | 
						|
 *  has been made (if any), and serves up appropriate responses.
 | 
						|
 *
 | 
						|
 *  \param[in] ConnectionState  Pointer to a TCP Connection State structure giving connection information
 | 
						|
 *  \param[in,out] Buffer       Pointer to the application's send/receive packet buffer
 | 
						|
 */
 | 
						|
void Webserver_ApplicationCallback(TCP_ConnectionState_t* const ConnectionState,
 | 
						|
                                   TCP_ConnectionBuffer_t* const Buffer)
 | 
						|
{
 | 
						|
	char*          BufferDataStr = (char*)Buffer->Data;
 | 
						|
	static uint8_t PageBlock     = 0;
 | 
						|
 | 
						|
	/* Check to see if a packet has been received on the HTTP port from a remote host */
 | 
						|
	if (TCP_APP_HAS_RECEIVED_PACKET(Buffer))
 | 
						|
	{
 | 
						|
		if (IsHTTPCommand(Buffer->Data, "GET"))
 | 
						|
		{
 | 
						|
			if (IsHTTPCommand(Buffer->Data, "GET / "))
 | 
						|
			{
 | 
						|
				PageBlock = 0;
 | 
						|
 | 
						|
				/* Copy the HTTP 200 response header into the packet buffer */
 | 
						|
				strcpy_P(BufferDataStr, HTTP200Header);
 | 
						|
 | 
						|
				/* Send the buffer contents to the host */
 | 
						|
				TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
 | 
						|
 | 
						|
				/* Lock the buffer to Device->Host transmissions only while we send the page contents */
 | 
						|
				TCP_APP_CAPTURE_BUFFER(Buffer);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* Copy the HTTP 404 response header into the packet buffer */
 | 
						|
				strcpy_P(BufferDataStr, HTTP404Header);
 | 
						|
 | 
						|
				/* Send the buffer contents to the host */
 | 
						|
				TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
 | 
						|
 | 
						|
				/* All data sent, close the connection */
 | 
						|
				TCP_APP_CLOSECONNECTION(ConnectionState);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (IsHTTPCommand(Buffer->Data, "HEAD"))
 | 
						|
		{
 | 
						|
			if (IsHTTPCommand(Buffer->Data, "HEAD / "))
 | 
						|
			{
 | 
						|
				/* Copy the HTTP response header into the packet buffer */
 | 
						|
				strcpy_P(BufferDataStr, HTTP200Header);
 | 
						|
 | 
						|
				/* Send the buffer contents to the host */
 | 
						|
				TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				/* Copy the HTTP response header into the packet buffer */
 | 
						|
				strcpy_P(BufferDataStr, HTTP404Header);
 | 
						|
 | 
						|
				/* Send the buffer contents to the host */
 | 
						|
				TCP_APP_SEND_BUFFER(Buffer, strlen(BufferDataStr));
 | 
						|
			}
 | 
						|
 | 
						|
			/* All data sent, close the connection */
 | 
						|
			TCP_APP_CLOSECONNECTION(ConnectionState);
 | 
						|
		}
 | 
						|
		else if (IsHTTPCommand(Buffer->Data, "TRACE"))
 | 
						|
		{
 | 
						|
			/* Echo the host's query back to the host */
 | 
						|
			TCP_APP_SEND_BUFFER(Buffer, Buffer->Length);
 | 
						|
 | 
						|
			/* All data sent, close the connection */
 | 
						|
			TCP_APP_CLOSECONNECTION(ConnectionState);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			/* Unknown request, just clear the buffer (drop the packet) */
 | 
						|
			TCP_APP_CLEAR_BUFFER(Buffer);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (TCP_APP_HAVE_CAPTURED_BUFFER(Buffer))
 | 
						|
	{
 | 
						|
		uint16_t RemLength = strlen_P(&HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE]);
 | 
						|
		uint16_t Length;
 | 
						|
 | 
						|
		/* Determine the length of the loaded block */
 | 
						|
		Length = ((RemLength > HTTP_REPLY_BLOCK_SIZE) ? HTTP_REPLY_BLOCK_SIZE : RemLength);
 | 
						|
 | 
						|
		/* Copy the next buffer sized block of the page to the packet buffer */
 | 
						|
		strncpy_P(BufferDataStr, &HTTPPage[PageBlock * HTTP_REPLY_BLOCK_SIZE], Length);
 | 
						|
 | 
						|
		/* Send the buffer contents to the host */
 | 
						|
		TCP_APP_SEND_BUFFER(Buffer, Length);
 | 
						|
 | 
						|
		/* Check to see if the entire page has been sent */
 | 
						|
		if (PageBlock++ == (sizeof(HTTPPage) / HTTP_REPLY_BLOCK_SIZE))
 | 
						|
		{
 | 
						|
			/* Unlock the buffer so that the host can fill it with future packets */
 | 
						|
			TCP_APP_RELEASE_BUFFER(Buffer);
 | 
						|
 | 
						|
			/* Close the connection to the host */
 | 
						|
			TCP_APP_CLOSECONNECTION(ConnectionState);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 |