Marco Oehler / Mbed OS Lab7
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers HTTPServer.cpp Source File

HTTPServer.cpp

00001 /*
00002  * HTTPServer.cpp
00003  * Copyright (c) 2020, ZHAW
00004  * All rights reserved.
00005  */
00006 
00007 #include <algorithm>
00008 #include "HTTPScript.h"
00009 #include "HTTPServer.h"
00010 
00011 using namespace std;
00012 
00013 inline string int2String(int i) {
00014     
00015     char buffer[32];
00016     sprintf(buffer, "%d", i);
00017     
00018     return string(buffer);
00019 }
00020 
00021 const unsigned int HTTPServer::INPUT_BUFFER_SIZE = 1024;    // size of receive buffer, given in [bytes]
00022 const int HTTPServer::SOCKET_TIMEOUT = 1000;                // timeout of socket, given in [ms]
00023 
00024 /**
00025  * Create and initialize an http server object.
00026  * @param ethernet a reference to the embedded TCP/IP stack to use.
00027  */
00028 HTTPServer::HTTPServer(EthernetInterface& ethernet) : ethernet(ethernet), thread(osPriorityNormal, STACK_SIZE) {
00029     
00030     // start thread
00031     
00032     thread.start(callback(this, &HTTPServer::run));
00033 }
00034 
00035 /**
00036  * Delete the http server object.
00037  */
00038 HTTPServer::~HTTPServer() {}
00039 
00040 /**
00041  * Registers the given script with the http server.
00042  * This allows to call a method of this script object
00043  * through virtual cgi-bin requests from a remote system.
00044  */
00045 void HTTPServer::add(string name, HTTPScript* httpScript) {
00046     
00047     httpScriptNames.push_back(name);
00048     httpScripts.push_back(httpScript);
00049 }
00050 
00051 /**
00052  * Decodes a given URL string into a standard text string.
00053  */
00054 string HTTPServer::urlDecoder(string url) {
00055     
00056     size_t pos = 0;
00057     while ((pos = url.find("+")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+1);
00058     while ((pos = url.find("%08")) != string::npos) url = url.substr(0, pos)+"\b"+url.substr(pos+3);
00059     while ((pos = url.find("%09")) != string::npos) url = url.substr(0, pos)+"\t"+url.substr(pos+3);
00060     while ((pos = url.find("%0A")) != string::npos) url = url.substr(0, pos)+"\n"+url.substr(pos+3);
00061     while ((pos = url.find("%0D")) != string::npos) url = url.substr(0, pos)+"\r"+url.substr(pos+3);
00062     while ((pos = url.find("%20")) != string::npos) url = url.substr(0, pos)+" "+url.substr(pos+3);
00063     while ((pos = url.find("%22")) != string::npos) url = url.substr(0, pos)+"\""+url.substr(pos+3);
00064     while ((pos = url.find("%23")) != string::npos) url = url.substr(0, pos)+"#"+url.substr(pos+3);
00065     while ((pos = url.find("%24")) != string::npos) url = url.substr(0, pos)+"$"+url.substr(pos+3);
00066     while ((pos = url.find("%25")) != string::npos) url = url.substr(0, pos)+"%"+url.substr(pos+3);
00067     while ((pos = url.find("%26")) != string::npos) url = url.substr(0, pos)+"&"+url.substr(pos+3);
00068     while ((pos = url.find("%2B")) != string::npos) url = url.substr(0, pos)+"+"+url.substr(pos+3);
00069     while ((pos = url.find("%2C")) != string::npos) url = url.substr(0, pos)+","+url.substr(pos+3);
00070     while ((pos = url.find("%2F")) != string::npos) url = url.substr(0, pos)+"/"+url.substr(pos+3);
00071     while ((pos = url.find("%3A")) != string::npos) url = url.substr(0, pos)+":"+url.substr(pos+3);
00072     while ((pos = url.find("%3B")) != string::npos) url = url.substr(0, pos)+";"+url.substr(pos+3);
00073     while ((pos = url.find("%3C")) != string::npos) url = url.substr(0, pos)+"<"+url.substr(pos+3);
00074     while ((pos = url.find("%3D")) != string::npos) url = url.substr(0, pos)+"="+url.substr(pos+3);
00075     while ((pos = url.find("%3E")) != string::npos) url = url.substr(0, pos)+">"+url.substr(pos+3);
00076     while ((pos = url.find("%3F")) != string::npos) url = url.substr(0, pos)+"?"+url.substr(pos+3);
00077     while ((pos = url.find("%40")) != string::npos) url = url.substr(0, pos)+"@"+url.substr(pos+3);
00078     
00079     return url;
00080 }
00081 
00082 /**
00083  * This <code>run()</code> method binds the TCP/IP server to a given port number
00084  * and enters an infinite loop that waits for http requests and then processes
00085  * these requests and returns a response.
00086  */
00087 void HTTPServer::run() {
00088     
00089     // bind the server to a given port number
00090     
00091     server.open(&ethernet);
00092     server.bind(PORT_NUMBER);
00093     server.listen();
00094     
00095     // enter infinite loop
00096     
00097     while (true) {
00098         
00099         TCPSocket* client = server.accept();
00100         if (client != NULL) {
00101             
00102             client->set_blocking(true);
00103             client->set_timeout(SOCKET_TIMEOUT); // set timeout of socket
00104             
00105             // read input
00106             
00107             char buffer[INPUT_BUFFER_SIZE];
00108             int size = client->recv(buffer, sizeof(buffer));
00109             
00110             if (size > 0) {
00111                 
00112                 string input(buffer, size);
00113                 string header;
00114                 string output;
00115                 
00116                 // parse input
00117                 
00118                 if ((input.find("GET") == 0) || (input.find("HEAD") == 0)) {
00119                     
00120                     if (input.find("cgi-bin") != string::npos) {
00121                         
00122                         // process script request with arguments
00123                         
00124                         string script = input.substr(input.find("cgi-bin/")+8, input.find(" ", input.find("cgi-bin/")+8)-input.find("cgi-bin/")-8);
00125                         string name;
00126                         vector<string> names;
00127                         vector<string> values;
00128                         
00129                         if (script.find("?") != string::npos) {
00130                             
00131                             name = script.substr(0, script.find("?"));
00132                             script = script.substr(script.find("?")+1);
00133                             
00134                             vector<string> arguments;
00135                             while (script.find("&") != string::npos) {
00136                                 arguments.push_back(script.substr(0, script.find("&")));
00137                                 script = script.substr(script.find("&")+1);
00138                             }
00139                             arguments.push_back(script);
00140                             
00141                             for (int i = 0; i < arguments.size(); i++) {
00142                                 
00143                                 if (arguments[i].find("=") != string::npos) {
00144                                     
00145                                     names.push_back(arguments[i].substr(0, arguments[i].find("=")));
00146                                     values.push_back(urlDecoder(arguments[i].substr(arguments[i].find("=")+1)));
00147                                     
00148                                 } else {
00149                                     
00150                                     names.push_back(arguments[i]);
00151                                     values.push_back("");
00152                                 }
00153                             }
00154                             
00155                         } else {
00156                             
00157                             name = script;
00158                         }
00159                         
00160                         // look for corresponding script
00161                         
00162                         for (int i = 0; i < min(httpScriptNames.size(), httpScripts.size()); i++) {
00163                             
00164                             if (httpScriptNames[i].compare(name) == 0) {
00165                                 
00166                                 output  = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n";
00167                                 output += "<!DOCTYPE html>\r\n";
00168                                 output += "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\r\n";
00169                                 output += "<body>\r\n";
00170                                 output += httpScripts[i]->call(names, values);
00171                                 output += "</body>\r\n";
00172                                 output += "</html>\r\n";
00173                                 
00174                                 header  = "HTTP/1.1 200 OK\r\n";
00175                                 header += "Content-Length: "+int2String(output.size())+"\r\n";
00176                                 header += "Content-Type: text/xml\r\n";
00177                                 header += "Expires: 0\r\n";
00178                                 header += "\r\n";
00179                                 
00180                                 output = header+output;
00181                             }
00182                         }
00183                         
00184                         // requested script was not found on this server
00185                         
00186                         if ((output).size() == 0) {
00187                             
00188                             output  = "<!DOCTYPE html>\r\n";
00189                             output += "<html lang=\"en\">\r\n";
00190                             output += "<head>\r\n";
00191                             output += "  <title>404 Not Found</title>\r\n";
00192                             output += "  <style type=\"text/css\">\r\n";
00193                             output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
00194                             output += "    p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n";
00195                             output += "  </style>\r\n";
00196                             output += "</head>\r\n";
00197                             output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
00198                             output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n";
00199                             output += "    <tr>\r\n";
00200                             output += "      <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n";
00201                             output += "    </tr>\r\n";
00202                             output += "    <tr>\r\n";
00203                             output += "      <td valign=\"top\">\r\n";
00204                             output += "      <p>The requested script could not be found on this server!</p>\r\n";
00205                             output += "      </td>\r\n";
00206                             output += "    </tr>\r\n";
00207                             output += "  </table>\r\n";
00208                             output += "</body>\r\n";
00209                             output += "</html>\r\n";
00210                             
00211                             header  = "HTTP/1.1 404 Not Found\r\n";
00212                             header += "Content-Length: "+int2String(output.size())+"\r\n";
00213                             header += "Content-Type: text/html\r\n";
00214                             header += "\r\n";
00215                             
00216                             output = header+output;
00217                         }
00218                         
00219                         // write output
00220                         
00221                         void* address = (void*)(output).c_str();
00222                         int offset = 0;
00223                         while (offset < (output).size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), (output).size()-offset);
00224                         
00225                     } else {
00226                         
00227                         // transmit static file
00228                         
00229                         output  = "<!DOCTYPE html>\r\n";
00230                         output += "<html lang=\"en\">\r\n";
00231                         output += "<head>\r\n";
00232                         output += "  <meta charset=\"utf-8\"/>\r\n";
00233                         output += "  <title>Sensor Fusion</title>\r\n";
00234                         output += "  <style type=\"text/css\">\r\n";
00235                         output += "    html {background-color: #223344;}\r\n";
00236                         output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
00237                         output += "    p, td {font-family:Helvetica,Arial,sans-serif; font-size: 16; color:#EEEEEE;}\r\n";
00238                         output += "  </style>\r\n";
00239                         output += "</head>\r\n";
00240                         output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
00241                         output += "  <script type=\"text/javascript\">\r\n";
00242                         output += "  var tiltAngleA = [];\r\n";
00243                         output += "  var tiltAngleG = [];\r\n";
00244                         output += "  var tiltAngleK = [];\r\n";
00245                         output += "  var tiltAngleC = [];\r\n";
00246                         output += "  var xmlhttp = null;\r\n";
00247                         output += "  var task = window.setInterval(\"update()\", 50);\r\n";
00248                         output += "  function update() {\r\n";
00249                         output += "    if (window.XMLHttpRequest) {\r\n";
00250                         output += "      xmlhttp = new XMLHttpRequest();\r\n";
00251                         output += "    } else if (window.ActiveXObject) {\r\n";
00252                         output += "      try {\r\n";
00253                         output += "        xmlhttp = new ActiveXObject(\"Msxml2.XMLHTTP\");\r\n";
00254                         output += "      } catch (exception) {\r\n";
00255                         output += "        try {\r\n";
00256                         output += "          xmlhttp = new ActiveXObject(\"Microsoft.XMLHTTP\");\r\n";
00257                         output += "        } catch (exception) {}\r\n";
00258                         output += "      }\r\n";
00259                         output += "    }\r\n";
00260                         output += "    xmlhttp.onreadystatechange = refresh;\r\n";
00261                         output += "    xmlhttp.open(\"GET\", \"/cgi-bin/tiltAngle\");\r\n";
00262                         output += "    xmlhttp.send(null);\r\n";
00263                         output += "  }\r\n";
00264                         output += "  function refresh() {\r\n";
00265                         output += "    if (xmlhttp.readyState == 4) {\r\n";
00266                         output += "      var xml = xmlhttp.responseXML;\r\n";
00267                         output += "      var floatValues = xml.getElementsByTagName(\"float\");\r\n";
00268                         output += "      tiltAngleA.push(floatValues[0].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleA.length > 400) tiltAngleA.shift();\r\n";
00269                         output += "      tiltAngleG.push(floatValues[1].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleG.length > 400) tiltAngleG.shift();\r\n";
00270                         output += "      tiltAngleK.push(floatValues[2].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleK.length > 400) tiltAngleK.shift();\r\n";
00271                         output += "      tiltAngleC.push(floatValues[3].childNodes[0].nodeValue/Math.PI*180.0); if (tiltAngleC.length > 400) tiltAngleC.shift();\r\n";
00272                         output += "      drawPlot(\"tiltAngle\", tiltAngleA, tiltAngleG, tiltAngleK, tiltAngleC, \"°\");\r\n";
00273                         output += "    }\r\n";
00274                         output += "  }\r\n";
00275                         output += "  function drawPlot(id, value0, value1, value2, value3, valueUnit) {\r\n";
00276                         output += "    var canvas = document.getElementById(id);\r\n";
00277                         output += "    var width = window.innerWidth-50;\r\n";
00278                         output += "    var height = window.innerHeight-50;\r\n";
00279                         output += "    canvas.width = 2*width;\r\n";
00280                         output += "    canvas.height = 2*height;\r\n";
00281                         output += "    canvas.style.width = width+\"px\";\r\n";
00282                         output += "    canvas.style.height = height+\"px\";\r\n";
00283                         output += "    var ctx = canvas.getContext(\"2d\");\r\n";
00284                         output += "    ctx.scale(2,2);\r\n";
00285                         output += "    ctx.fillStyle = \"#334455\";\r\n";
00286                         output += "    ctx.fillRect(0.5, 0.5, width-1, height-1);\r\n";
00287                         output += "    var valueMin = value0[0];\r\n";
00288                         output += "    var valueMax = value0[0];\r\n";
00289                         output += "    for (i = 0; i < Math.min(Math.min(value0.length, value1.length), value2.length); i++) {\r\n";
00290                         output += "      valueMin = Math.min(valueMin, Math.min(value0[i], Math.min(value1[i], Math.min(value2[i], value3[i]))));\r\n";
00291                         output += "      valueMax = Math.max(valueMax, Math.max(value0[i], Math.max(value1[i], Math.max(value2[i], value3[i]))));\r\n";
00292                         output += "    }\r\n";
00293                         output += "    if (valueMax-valueMin < 2.0/Math.pow(10.0, 3)) {\r\n";
00294                         output += "      var valueMean = (valueMin+valueMax)/2.0;\r\n";
00295                         output += "      valueMin = valueMean-1.0/Math.pow(10.0, 3);\r\n";
00296                         output += "      valueMax = valueMean+1.0/Math.pow(10.0, 3);\r\n";
00297                         output += "    }\r\n";
00298                         output += "    var valueStep = (valueMax-valueMin)/(height/100); if (valueStep < 1.0/Math.pow(10.0, 3)) valueStep = 1.0/Math.pow(10.0, 3);\r\n";
00299                         output += "    var valueGain = Math.pow(10.0, Math.floor(Math.log(valueStep)/Math.log(10.0)));\r\n";
00300                         output += "    valueStep = valueStep/valueGain;\r\n";
00301                         output += "    if (valueStep > 5.0) valueStep = 5.0*valueGain; else if (valueStep > 2.0) valueStep = 2.0*valueGain; else valueStep = valueGain;\r\n";
00302                         output += "    valueMin = Math.floor(valueMin/valueStep-0.25)*valueStep;\r\n";
00303                         output += "    valueMax = Math.ceil(valueMax/valueStep+0.25)*valueStep;\r\n";
00304                         output += "    ctx.strokeStyle = \"#EEEEEE\";\r\n";
00305                         output += "    ctx.lineWidth = 1;\r\n";
00306                         output += "    ctx.beginPath();\r\n";
00307                         output += "    for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n";
00308                         output += "      ctx.moveTo(0, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n";
00309                         output += "      ctx.lineTo(width, (valueMax-valueCurrent)/(valueMax-valueMin)*height+0.5);\r\n";
00310                         output += "    }\r\n";
00311                         output += "    ctx.stroke();\r\n";
00312                         
00313                         output += "    ctx.font = \"normal 16px sans-serif\";\r\n";
00314                         output += "    ctx.textBaseline = \"bottom\";\r\n";
00315                         output += "    ctx.fillStyle = \"white\";\r\n";
00316                         output += "    for (valueCurrent = valueMin+valueStep; valueCurrent < valueMax-valueStep/2.0; valueCurrent += valueStep) {\r\n";
00317                         output += "      ctx.fillText(valueCurrent.toFixed(2), 10.0, (valueMax-valueCurrent)/(valueMax-valueMin)*height-5.0);\r\n";
00318                         output += "    }\r\n";
00319                         output += "    ctx.fillStyle = \"#FF0000\";\r\n";
00320                         output += "    ctx.fillText(\"Tilt Angle from Accelerometer: \"+(value0[value0.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 40);\r\n";
00321                         output += "    ctx.fillStyle = \"#FFFF00\";\r\n";
00322                         output += "    ctx.fillText(\"Tilt Angle from Gyro: \"+(value1[value1.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 65);\r\n";
00323                         output += "    ctx.fillStyle = \"#00FF00\";\r\n";
00324                         output += "    ctx.fillText(\"Tilt Angle from Kalman-Filter: \"+(value2[value2.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 90);\r\n";
00325                         output += "    ctx.fillStyle = \"#00AA00\";\r\n";
00326                         output += "    ctx.fillText(\"Tilt Angle from Complementary Filter: \"+(value3[value3.length-1]*1.0).toFixed(3)+\" [\"+valueUnit+\"]\", width/2.0, 115);\r\n";
00327                         
00328                         output += "    ctx.strokeStyle = \"#FF0000\";\r\n";
00329                         output += "    ctx.lineWidth = 2;\r\n";
00330                         output += "    ctx.beginPath();\r\n";
00331                         output += "    ctx.moveTo(0, (valueMax-value0[0])/(valueMax-valueMin)*height+0.5);\r\n";
00332                         output += "    for (i = 1; i < value0.length; i++) {\r\n";
00333                         output += "      ctx.lineTo(i/(value0.length-1)*width, (valueMax-value0[i])/(valueMax-valueMin)*height+0.5);\r\n";
00334                         output += "    }\r\n";
00335                         output += "    ctx.stroke();\r\n";
00336                         
00337                         output += "    ctx.strokeStyle = \"#FFFF00\";\r\n";
00338                         output += "    ctx.lineWidth = 2;\r\n";
00339                         output += "    ctx.beginPath();\r\n";
00340                         output += "    ctx.moveTo(0, (valueMax-value1[0])/(valueMax-valueMin)*height+0.5);\r\n";
00341                         output += "    for (i = 1; i < value1.length; i++) {\r\n";
00342                         output += "      ctx.lineTo(i/(value1.length-1)*width, (valueMax-value1[i])/(valueMax-valueMin)*height+0.5);\r\n";
00343                         output += "    }\r\n";
00344                         output += "    ctx.stroke();\r\n";
00345                         
00346                         output += "    ctx.strokeStyle = \"#00FF00\";\r\n";
00347                         output += "    ctx.lineWidth = 2;\r\n";
00348                         output += "    ctx.beginPath();\r\n";
00349                         output += "    ctx.moveTo(0, (valueMax-value2[0])/(valueMax-valueMin)*height+0.5);\r\n";
00350                         output += "    for (i = 1; i < value2.length; i++) {\r\n";
00351                         output += "      ctx.lineTo(i/(value2.length-1)*width, (valueMax-value2[i])/(valueMax-valueMin)*height+0.5);\r\n";
00352                         output += "    }\r\n";
00353                         output += "    ctx.stroke();\r\n";
00354                         
00355                         output += "    ctx.strokeStyle = \"#00AA00\";\r\n";
00356                         output += "    ctx.lineWidth = 2;\r\n";
00357                         output += "    ctx.beginPath();\r\n";
00358                         output += "    ctx.moveTo(0, (valueMax-value3[0])/(valueMax-valueMin)*height+0.5);\r\n";
00359                         output += "    for (i = 1; i < value3.length; i++) {\r\n";
00360                         output += "      ctx.lineTo(i/(value3.length-1)*width, (valueMax-value3[i])/(valueMax-valueMin)*height+0.5);\r\n";
00361                         output += "    }\r\n";
00362                         output += "    ctx.stroke();\r\n";
00363                         
00364                         output += "    ctx.strokeStyle = \"white\";\r\n";
00365                         output += "    ctx.lineWidth = 1;\r\n";
00366                         output += "    ctx.strokeRect(0.5, 0.5, width-1, height-1);\r\n";
00367                         output += "  }\r\n";
00368                         output += "  </script>";
00369                         output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"20\" cellpadding=\"0\">\r\n";
00370                         output += "    <tr>\r\n";
00371                         output += "      <th><canvas id=\"tiltAngle\"></canvas></th>\r\n";
00372                         output += "    </tr>\r\n";
00373                         output += "  </table>\r\n";
00374                         output += "</body>\r\n";
00375                         output += "</html>\r\n";
00376                         
00377                         header  = "HTTP/1.1 404 Not Found\r\n";
00378                         header += "Content-Length: "+int2String(output.size())+"\r\n";
00379                         header += "Content-Type: text/html\r\n";
00380                         header += "\r\n";
00381                         
00382                         output = header+output;
00383                         
00384                         // write output
00385                         
00386                         void* address = (void*)output.c_str();
00387                         int offset = 0;
00388                         while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset);
00389                     }
00390                     
00391                 } else {
00392                     
00393                     // the http method is not known
00394                     
00395                     output  = "<!DOCTYPE html>\r\n";
00396                     output += "<html lang=\"en\">\r\n";
00397                     output += "<head>\r\n";
00398                     output += "  <title>400 Bad Request</title>\r\n";
00399                     output += "  <style type=\"text/css\">\r\n";
00400                     output += "    h2 {font-family:Helvetica,Arial,sans-serif; font-size: 24; color:#FFFFFF;}\r\n";
00401                     output += "    p {font-family:Helvetica,Arial,sans-serif; font-size: 14; color:#444444;}\r\n";
00402                     output += "  </style>\r\n";
00403                     output += "</head>\r\n";
00404                     output += "<body leftmargin=\"0\" topmargin=\"0\" marginwidth=\"0\" marginheight=\"0\">\r\n";
00405                     output += "  <table width=\"100%\" height=\"100%\" border=\"0\" frame=\"void\" cellspacing=\"0\" cellpadding=\"20\">\r\n";
00406                     output += "    <tr>\r\n";
00407                     output += "      <th width=\"100%\" height=\"30\" bgcolor=\"#0064A6\"><h2>400 Bad Request</h2></th>\r\n";
00408                     output += "    </tr>\r\n";
00409                     output += "    <tr>\r\n";
00410                     output += "      <td valign=\"top\">\r\n";
00411                     output += "      <p>The requested method is not supported by this server!</p>\r\n";
00412                     output += "      </td>\r\n";
00413                     output += "    </tr>\r\n";
00414                     output += "  </table>\r\n";
00415                     output += "</body>\r\n";
00416                     output += "</html>\r\n";
00417                     
00418                     header  = "HTTP/1.1 400 Bad Request\r\n";
00419                     header += "Content-Length: "+int2String(output.size())+"\r\n";
00420                     header += "Content-Type: text/html\r\n";
00421                     header += "\r\n";
00422                     
00423                     output = header+output;
00424                     
00425                     // write output
00426                     
00427                     void* address = (void*)output.c_str();
00428                     int offset = 0;
00429                     while (offset < output.size()) offset += client->send((void*)(static_cast<int>(reinterpret_cast<intptr_t>(address))+offset), output.size()-offset);
00430                 }
00431             }
00432             
00433             client->close();
00434             
00435         } // client != NULL
00436         
00437     } // infinite while loop
00438 }
00439