Skip to content

Commit

Permalink
Add buffering for all output
Browse files Browse the repository at this point in the history
Update WebServer::write(uint8_t) to write to a buffer instead of sending
single characters (or short strings) as small packets.  Remove the other
signatures of write so that the base ones in the Print class (which call
write(uint8_t)) are used instead and simplify the writeP/printP
definitions to do this too.

This greatly improves the performance of pages which are built from a
large number of small strings or values at the expense of a small
additional amount of memory (which can be adjusted with the use of a new
macro called WEBDUINO_OUTPUT_BUFFER_SIZE) and also saves ~85 bytes of
flash.
  • Loading branch information
ribbons committed Jan 16, 2014
1 parent 7b746b6 commit 8ce7dbc
Showing 1 changed file with 31 additions and 44 deletions.
75 changes: 31 additions & 44 deletions WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@
#define WEBDUINO_SERVER_ERROR_MESSAGE "<h1>500 Internal Server Error</h1>"
#endif // WEBDUINO_SERVER_ERROR_MESSAGE

#ifndef WEBDUINO_OUTPUT_BUFFER_SIZE
#define WEBDUINO_OUTPUT_BUFFER_SIZE 32
#endif // WEBDUINO_OUTPUT_BUFFER_SIZE

// add '#define WEBDUINO_FAVICON_DATA ""' to your application
// before including WebServer.h to send a null file as the favicon.ico file
// otherwise this defaults to a 16x16 px black diode on blue ground
Expand Down Expand Up @@ -295,9 +299,6 @@ class WebServer: public Print

// implementation of write used to implement Print interface
virtual size_t write(uint8_t);
virtual size_t write(const char *str);
virtual size_t write(const uint8_t *buffer, size_t size);
size_t write(const char *data, size_t length);

// tells if there is anything to process
uint8_t available();
Expand All @@ -324,6 +325,9 @@ class WebServer: public Print
unsigned char m_cmdCount;
UrlPathCommand *m_urlPathCmd;

uint8_t m_buffer[WEBDUINO_OUTPUT_BUFFER_SIZE];
uint8_t m_bufFill;

void reset();
void getRequest(WebServer::ConnectionType &type, char *request, int *length);
bool dispatchCommand(ConnectionType requestType, char *verb,
Expand All @@ -337,6 +341,7 @@ class WebServer: public Print
char *url_tail, bool tail_complete);
void noRobots(ConnectionType type);
void favicon(ConnectionType type);
void flushBuf();
};

/* define this macro if you want to include the header in a sketch source
Expand All @@ -357,7 +362,8 @@ WebServer::WebServer(const char *urlPrefix, int port) :
m_failureCmd(&defaultFailCmd),
m_defaultCmd(&defaultFailCmd),
m_cmdCount(0),
m_urlPathCmd(NULL)
m_urlPathCmd(NULL),
m_bufFill(0)
{
}

Expand Down Expand Up @@ -392,70 +398,49 @@ void WebServer::setUrlPathCommand(UrlPathCommand *cmd)

size_t WebServer::write(uint8_t ch)
{
return m_client.write(ch);
}
m_buffer[m_bufFill++] = ch;

size_t WebServer::write(const char *str)
{
return m_client.write(str);
}
if(m_bufFill == sizeof(m_buffer))
{
m_client.write(m_buffer, sizeof(m_buffer));
m_bufFill = 0;
}

size_t WebServer::write(const uint8_t *buffer, size_t size)
{
return m_client.write(buffer, size);
return sizeof(ch);
}

size_t WebServer::write(const char *buffer, size_t length)
void WebServer::flushBuf()
{
return m_client.write((const uint8_t *)buffer, length);
if(m_bufFill > 0)
{
m_client.write(m_buffer, m_bufFill);
m_bufFill = 0;
}
}

void WebServer::writeP(const unsigned char *data, size_t length)
{
// copy data out of program memory into local storage, write out in
// chunks of 32 bytes to avoid extra short TCP/IP packets
uint8_t buffer[32];
size_t bufferEnd = 0;
// copy data out of program memory into local storage

while (length--)
{
if (bufferEnd == 32)
{
m_client.write(buffer, 32);
bufferEnd = 0;
}

buffer[bufferEnd++] = pgm_read_byte(data++);
write(pgm_read_byte(data++));
}

if (bufferEnd > 0)
m_client.write(buffer, bufferEnd);
}

void WebServer::printP(const unsigned char *str)
{
// copy data out of program memory into local storage, write out in
// chunks of 32 bytes to avoid extra short TCP/IP packets
uint8_t buffer[32];
size_t bufferEnd = 0;
// copy data out of program memory into local storage

while ((buffer[bufferEnd++] = pgm_read_byte(str++)))
while (uint8_t value = pgm_read_byte(str++))
{
if (bufferEnd == 32)
{
m_client.write(buffer, 32);
bufferEnd = 0;
}
write(value);
}

// write out everything left but trailing NUL
if (bufferEnd > 1)
m_client.write(buffer, bufferEnd - 1);
}

void WebServer::printCRLF()
{
m_client.write((const uint8_t *)"\r\n", 2);
print(CRLF);
}

bool WebServer::dispatchCommand(ConnectionType requestType, char *verb,
Expand Down Expand Up @@ -603,6 +588,8 @@ void WebServer::processConnection(char *buff, int *bufflen)
m_failureCmd(*this, requestType, buff, (*bufflen) >= 0);
}

flushBuf();

#if WEBDUINO_SERIAL_DEBUGGING > 1
Serial.println("*** stopping connection ***");
#endif
Expand Down

0 comments on commit 8ce7dbc

Please sign in to comment.