Results 1 to 2 of 2

Thread: A simple HTTP server going wrong.

  1. #1
    Join Date
    Nov 2008
    Posts
    38
    Thanks
    4
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11

    Unhappy A simple HTTP server going wrong.

    Hello, and thanks for reading. Perhaps my issues are more about the HTTP protocol than Qt, but here goes...

    The code at the bottom is my simple prototype HTTP server for a web interface for my app. qWarning ouputs the lengths of the headers it receives and its POST contents, raw and interpreted. It responds to GET requests with a little form containing two fields, that much works fine.

    I thought this would be a matter of reading headers, followed by reading arbitrary data. Apparently not, since the behaviour is very inconsistent.

    For orientation, here's the qWarning output when the page is used in Firefox, submitting nothing in input1 and the string "x" in input2 (some headers omitted for clarity)

    Qt Code:
    1. POST:20
    2. Content-Type::49
    3. Content-Length::20
    4. Blank
    5. 16 bytes
    6. Headers done
    7.  
    8. input1=&input2=x
    9. input1 =>
    10. input2 => x
    To copy to clipboard, switch view to plain text mode 

    All present and correct.

    In Konqueror, however, the GET page works fine but hitting the post button causes a "Connection to host is broken" message. Despite this, the program outputs this (some headers omitted again, differences are included):
    Qt Code:
    1. POST:20
    2. Pragma::18
    3. Cache-control::25
    4. Content-Type::49
    5. Headers done
    6.  
    7.  
    8. =>
    To copy to clipboard, switch view to plain text mode 
    Note that there is a Content-Type header but not a Content-length. What's going on here? Notice that no blank header-ending line is present either.

    Even more confusing is behaviour in Opera. If input1 has contents, everything works fine. If input2 has contents but input1 does not then it very often sets the Content-Length header properly but when the "content" variable (see code) is read, there is nothing there. Sometimes, rarely, arbitrarily, the data is there.

    Here's the code for this little headache. Am I using the Qt objects incorrectly or am I misunderstanding the HTTP protocol?

    To summarise:

    Why does Konqueror say connection failed for POST requests, even though the code executes?

    Why does the "content" variable not always contain data, even when Content-Length is correctly set?

    And finally, why does ~HTTPRequest never get called even though the socket closes and the socket is its parent object? (I tried calling delete explicitly but that broke everything?)

    Qt Code:
    1. HTTPInterface :: HTTPInterface (QString pass, unsigned int port, QObject * p)
    2. : QTcpServer (p) {
    3. password = pass;
    4. if (!pass.size()) {_ok=false;return;}
    5.  
    6. connect(this,SIGNAL(newConnection()),
    7. this,SLOT(incoming()) );
    8.  
    9. _ok = listen (QHostAddress::Any, port);
    10. }
    11.  
    12. bool HTTPInterface :: ok () const {return _ok;}
    13.  
    14. void HTTPInterface :: incoming () {
    15. while (QTcpSocket * connection = nextPendingConnection()) {
    16. new HTTPRequest (connection);
    17. }
    18. }
    19.  
    20. HTTPRequest :: HTTPRequest (QTcpSocket * s) : QObject (s), socket (s) {
    21. connect(s,SIGNAL(readyRead()),
    22. this,SLOT(respond()) );
    23. }
    24.  
    25. HTTPRequest :: ~HTTPRequest () {
    26. qWarning ("~HTTPRequest");
    27. }
    28.  
    29. namespace {
    30. QString title = "Remote Administration";
    31. QString page = "http://foo.com";
    32. QString heading =
    33. "<h1>"+title+"</h1>\n"
    34. "<h2><a href=\"" + page + "\">" + page + "</a></h2>\n";
    35. QString stylesheet =
    36. "\n<style type=\"text/css\">\n"
    37. "h1 {\n"
    38. "\tcolor: red;\n"
    39. "}\n"
    40. "</style>\n\n";
    41.  
    42. QRegExp header_space ("[\\s\\n\\r]+");
    43. QRegExp anything ("[^\\s\\n\\r]");
    44. QRegExp post_var ("([^=]+)=([^&]*)");
    45. };
    46.  
    47. void HTTPRequest :: respond () {
    48. QTextStream out (socket);
    49.  
    50. while (socket->canReadLine()) {
    51. QString l = socket -> readLine ();
    52.  
    53. // Headers end with a blank line.
    54. if (anything.indexIn(l) < 0) {
    55. qWarning("Blank");
    56. // If there's non-header content, read it.
    57. if (headers.contains("Content-Length:")) {
    58. l = headers["Content-Length:"][1];
    59. content = socket -> read(l.toLong());
    60. qWarning(QString("%1 bytes").arg(l.toLong())
    61. .toAscii());
    62. }
    63. continue;
    64. }
    65.  
    66. // Save each header, indexed by the "FOO:" prefix.
    67. QStringList tokens = l.split (header_space);
    68. foreach (QString t, tokens) {
    69. headers[tokens[0]] = tokens;
    70. }
    71. qWarning(QString("%1:%2")
    72. .arg(tokens[0]).arg(l.size()).toAscii() );
    73. }
    74. qWarning("Headers done\n");
    75.  
    76. out << "HTTP/1.0 200 Ok\r\n"
    77. "Content-Type: text/html; charset=\"utf-8\"\r\n"
    78. "\r\n"
    79. "<html><head><title>" << title << "</title></head>\n"
    80. "<body>" << stylesheet << heading;
    81.  
    82. // Interpret POST.
    83. qWarning(content);
    84. QStringList post_vars = QString(content).split('&');
    85. foreach (QString pair, post_vars) {
    86. QString key = pair.section('=',0,0);
    87. QString val = pair.section('=',1);
    88. qWarning(QString("%1 => %2").arg(key).arg(val).toAscii());
    89. key = QUrl::fromPercentEncoding (key.toAscii());
    90. val = QUrl::fromPercentEncoding (val.toAscii());
    91. POST[key] = val;
    92. }
    93.  
    94. if (headers.contains("POST")) {
    95. out << "<h3>POST</h3><table><tbody>\n";
    96. for (QMapIterator<QString,QString> i(POST); i.hasNext(); ) {
    97. i.next();
    98. out << "\t<tr><td>" << i.key()
    99. << "</td><td>" << i.value() << "</td></tr>\n";
    100. }
    101. out << "</tbody></table>\n";
    102. }
    103.  
    104. else { // Everything else defaults to GET.
    105. out << "<p><form method=\"post\" action=\"act\">\n"
    106. "\t<input type=\"text\" name=\"input1\" />\n"
    107. "\t<input type=\"text\" name=\"input2\" />\n"
    108. "\t<input type=\"submit\" /></form>\n</p>\n";
    109. }
    110.  
    111. socket->close();
    112. }
    To copy to clipboard, switch view to plain text mode 

  2. #2
    Join Date
    Dec 2006
    Posts
    849
    Thanks
    6
    Thanked 163 Times in 151 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: A simple HTTP server going wrong.

    Just to be on the safe side: tcp connections may deliver data in several packets. canReadLine()==false does not mean that all the data you sent has been received and processed. It just means that the data already available (in full lines) has been processed.
    Make sure you are prepared for your header to arrive in multiple pieces (i.e. do not start processing an incomplete header).

    HTH

Similar Threads

  1. [java] write a simple server
    By mickey in forum General Programming
    Replies: 0
    Last Post: 22nd July 2008, 00:59
  2. realtime_plot example problem--help needed.
    By swamyonline in forum Qwt
    Replies: 8
    Last Post: 17th July 2008, 19:12
  3. Build an HTTP server
    By the_bis in forum Qt Programming
    Replies: 4
    Last Post: 30th March 2007, 07:36

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.