Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r56365 - in sandbox/SOC/2007/cgi/branches/pickmeup: boost/cgi/common boost/cgi/fcgi libs/cgi/build/msvc/9.0/Boost.CGI libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser libs/cgi/example/fcgi/echo libs/cgi/example/fcgi/file_browser
From: lists.drrngrvy_at_[hidden]
Date: 2009-09-23 08:29:57


Author: drrngrvy
Date: 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
New Revision: 56365
URL: http://svn.boost.org/trac/boost/changeset/56365

Log:
Bug fixes for FastCGI. Tested on Windows XP with MSVC9.0. Binary reads / writes seem stable now with large files, if a bit slow.
Binary files modified:
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.ncb
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.suo
Text files modified:
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/header.hpp | 11 ++---
   sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp | 49 ++++++++++++++++----------
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj | 6 ++-
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp | 29 +++++----------
   sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp | 73 +++++++++++++++++++++++++--------------
   5 files changed, 94 insertions(+), 74 deletions(-)

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/header.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/header.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/common/header.hpp 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
@@ -52,6 +52,10 @@
        : content("Set-cookie: " + ck.to_string())
      {
      }
+
+ operator string_type () {
+ return content + "\r\n";
+ }
 
      string_type content;
    };
@@ -115,13 +119,6 @@
      return basic_header<CharT>("Content-encoding", str);
    }
 
- template<typename CharT, typename T> basic_header<CharT>
- content_length(const T& t)
- {
- return basic_header<CharT>("Content-length",
- boost::lexical_cast<std::basic_string<CharT> >(t));
- }
-
    template<typename CharT> basic_header<CharT>
      content_length(const CharT * t)
    {

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/boost/cgi/fcgi/client.hpp 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
@@ -124,26 +124,36 @@
     boost::system::error_code
       close(boost::uint64_t app_status, boost::system::error_code& ec)
     {
- if (status_ == closed_) return ec;
-
- outbuf_.clear();
- header_.reset(spec_detail::END_REQUEST, request_id_, 8);
- // Write an EndRequest packet to the server.
-
- //BOOST_ASSERT(role_ == fcgi::spec_detail::RESPONDER
- // && "Only supports Responder role for now (**FIXME**)");
-
- fcgi::spec::end_request_body body(
- app_status, fcgi::spec_detail::REQUEST_COMPLETE);
+ // We can safely ignore this next bit when the connection
+ // is already closed. This might happen when the client aborts
+ // the connection.
+ if (!ec && status_ != closed_ && connection_->is_open())
+ {
+ outbuf_.clear();
+ header_.reset(spec_detail::END_REQUEST, request_id_, 8);
 
- outbuf_.push_back(header_.data());
- outbuf_.push_back(body.data());
+ // Write an EndRequest packet to the server.
+ fcgi::spec::end_request_body body(
+ app_status, fcgi::spec_detail::REQUEST_COMPLETE);
 
- write(*connection_, outbuf_, boost::asio::transfer_all(), ec);
+ outbuf_.push_back(header_.data());
+ outbuf_.push_back(body.data());
 
- if (!ec && !keep_connection_)
- connection_->close();
+ write(*connection_, outbuf_, boost::asio::transfer_all(), ec);
 
+ if (!ec && !keep_connection_)
+ {
+ connection_->close();
+ }
+ }
+
+ if (ec && !keep_connection_)
+ {
+ // If there was an error writing to the client, we can ignore it
+ // unless the `keep_connection_` flag is set.
+ // The client has likely aborted the request if we reach here.
+ ec = boost::system::error_code();
+ }
       return ec;
     }
 
@@ -188,8 +198,6 @@
       {
         boost::asio::const_buffer buffer(*iter);
         std::size_t new_buf_size( boost::asio::buffer_size(*iter) );
- std::cerr<< "-" << new_buf_size << "-";
- // Only write a maximum of 65535 bytes.
         if (total_buffer_size + new_buf_size
> static_cast<std::size_t>(fcgi::spec::max_packet_size::value))
         {
@@ -200,8 +208,10 @@
           {
             total_buffer_size
               = std::min<std::size_t>(new_buf_size,65500);
+ /*
             std::cerr<< "Oversized buffer: " << total_buffer_size
                      << " / " << new_buf_size << " bytes sent\n";
+ */
             outbuf_.push_back(
               boost::asio::buffer(*iter, total_buffer_size));
             break;
@@ -221,13 +231,14 @@
         = boost::asio::write(*connection_, outbuf_
                             , boost::asio::transfer_all(), ec);
 
+ /*
       std::cerr<< "Transferred " << bytes_transferred
                << " / " << total_buffer_size << " bytes (running total: "
                << total_sent_bytes_ << "; "
                << total_sent_packets_ << " packets).\n";
       if (ec)
         std::cerr<< "Error " << ec << ": " << ec.message() << '\n';
-
+ */
       total_sent_bytes_ += bytes_transferred;
       total_sent_packets_ += 1;
       // Now remove the protocol overhead from the caller, who

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.ncb
==============================================================================
Binary files. No diff available.

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/Boost.CGI.suo
==============================================================================
Binary files. No diff available.

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/build/msvc/9.0/Boost.CGI/fcgi_file_browser/fcgi_file_browser.vcproj 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
@@ -114,11 +114,13 @@
                         />
                         <Tool
                                 Name="VCCLCompilerTool"
- Optimization="2"
+ Optimization="3"
                                 EnableIntrinsicFunctions="true"
                                 PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
                                 RuntimeLibrary="2"
                                 EnableFunctionLevelLinking="true"
+ DisableLanguageExtensions="false"
+ RuntimeTypeInfo="false"
                                 UsePrecompiledHeader="0"
                                 WarningLevel="3"
                                 DebugInformationFormat="3"
@@ -135,7 +137,7 @@
                         <Tool
                                 Name="VCLinkerTool"
                                 LinkIncremental="1"
- GenerateDebugInformation="true"
+ GenerateDebugInformation="false"
                                 SubSystem="1"
                                 OptimizeReferences="2"
                                 EnableCOMDATFolding="2"

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/echo/main.cpp 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
@@ -150,18 +150,9 @@
   resp<< "Response content-length == "
       << resp.content_length(); // the content-length (returns std::size_t)
 
- // This function finishes up:
- return commit(req, resp, 0);
- //
- // It is equivalent to the below, where the third argument is represented by
- // `program_status`:
- //
- // resp.send(req.client());
- // req.close(resp.status(), program_status);
- // return program_status;
- //
- // Note: in this case `program_status == 0`.
- //
+ // This function finishes up. The optional third argument
+ // is the program status (default: 0).
+ return commit(req, resp);
 }
 
 int main()
@@ -197,7 +188,7 @@
     for (;;)
     {
       a.accept(req);
- //cerr<< "Accepted" << endl;
+ cerr<< "Accepted new request.\n";
       ret = handle_request(req);
       if (ret)
         break;
@@ -214,15 +205,15 @@
 
 }catch(boost::system::system_error const& se){
   // This is the type of error thrown by the library.
- //cerr<< "[fcgi] System error: " << se.what() << endl;
- return 1313;
+ cerr<< "[fcgi] System error: " << se.what() << endl;
+ return -1;
 }catch(std::exception const& e){
   // Catch any other exceptions
- //cerr<< "[fcgi] Exception: " << e.what() << endl;
- return 666;
+ cerr<< "[fcgi] Exception: " << e.what() << endl;
+ return -2;
 }catch(...){
- //cerr<< "[fcgi] Uncaught exception!" << endl;
- return 667;
+ cerr<< "[fcgi] Uncaught exception!" << endl;
+ return -3;
 }
 }
 //]

Modified: sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp
==============================================================================
--- sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp (original)
+++ sandbox/SOC/2007/cgi/branches/pickmeup/libs/cgi/example/fcgi/file_browser/main.cpp 2009-09-23 08:29:56 EDT (Wed, 23 Sep 2009)
@@ -97,6 +97,9 @@
   if (filetype == "ogg")
     return "audio/ogg";
   else
+ if (filetype == "flac")
+ return "audio/flac";
+ else
   if (filetype == "mp3")
     return "audio/mpeg";
   else
@@ -145,7 +148,9 @@
 }
 
 template<typename Response, typename Client>
-void show_file(Response& resp, Client& client, fs::path const& file)
+boost::system::error_code& show_file(
+ Response& resp, Client& client, fs::path const& file
+ , boost::system::error_code& ec)
 {
   if (!fs::exists(file))
     resp<< content_type("text/plain")
@@ -154,7 +159,7 @@
   {
     boost::uintmax_t size (fs::file_size(file));
     cerr<< "size: " << size << endl;
- if (size > 200000000L) // Files must be < 200MB
+ if (size > 750000000L) // Files must be < 750MB (this is arbitrary).
       resp<< "File too large.";
     else
     {
@@ -162,42 +167,52 @@
       std::string mime_type (get_mime_type(file));
       if (!mime_type.empty())
       {
+ // Write unbuffered (ie. not using a response). This makes sense
+ // for large files, which would take up too much memory to
+ // buffer.
+ // First, some debugging to the console.
         cerr<< "MIME-type: " << mime_type << '\n';
         cerr<< "File size: " << size << '\n';
- std::string ctype (content_type(mime_type).content + "\r\n\r\n");
- write(client, boost::asio::buffer(clen));
- write(client, boost::asio::buffer(ctype));
         /// Open the file and read it as binary data.
         ifstream ifs (file.string().c_str(), std::ios::binary);
         if (ifs.is_open())
         {
- resp<< content_type(mime_type);
- //resp.flush(client);
- boost::uintmax_t bufsize = 1000;
+ // Write out the response headers.
+ std::string ctype (content_type(mime_type));
+ std::string clen (content_length<char>(size));
+ clen += "\r\n";
+ write(client, boost::asio::buffer(ctype));
+ write(client, boost::asio::buffer(clen));
+ // Read then write up to 1MB at a time.
+ boost::uintmax_t bufsize = 1000000;
           boost::uintmax_t read_bytes;
- char buf[1000];
+ char buf[1000000];
           ifs.seekg(0, std::ios::beg);
- while (!ifs.eof() && size > 0)
+ while (!ifs.eof() && size > 0 && !ec)
           {
             ifs.read(buf, size < bufsize ? size : bufsize);
             read_bytes = ifs.gcount();
             size -= read_bytes;
- cerr<< "Read " << read_bytes << " bytes from the file.\n";
- //if (resp.content_length() + read_bytes >= 65000)
- // resp.flush(client);
- //resp.write(buf, read_bytes);
- write(client, boost::asio::buffer(buf, read_bytes));
- //resp.flush(client);
+ //cerr<< "Read " << read_bytes << " bytes from the file.\n";
+ // Write unbuffered (ie. not using a response).
+ write(client, boost::asio::buffer(buf, read_bytes)
+ , boost::asio::transfer_all(), ec);
           }
- //resp.send(client);
- //cerr<< "Content-length: " << resp.content_length() << '\n';
+ }
+ else
+ {
+ resp<< content_type("text/plain")
+ << "File cannot be opened. Please try again later.";
         }
       }
       else
+ {
         resp<< content_type("text/plain")
             << "File type not allowed.";
+ }
     }
   }
+ return ec;
 }
     
 template<typename Response>
@@ -229,12 +244,10 @@
       }
       else
       {
- // display filename only.
+ // Display only the filename.
         resp<< "<li class=\"file\"><a href=\"?file="
             << iter->string() << "\">" << iter->path().filename()
             << "</a>";
- //if (fs::is_regular_file(iter->status()))
- // resp<< " [" << fs::file_size(iter->path()) << " bytes]";
         resp<< "</li>\n";
       }
     }
@@ -265,9 +278,15 @@
 
   if (req.get.count("file"))
   {
- show_file(resp, req.client(), req.get["file"]);
- req.close(resp.status(), 0);
- return 0; //commit(req, resp);
+ boost::system::error_code ec;
+ show_file(resp, req.client(), req.get["file"], ec);
+ if (ec)
+ {
+ cerr<< "Writing file finished unexpectedly!\n"
+ " Error " << ec << ": " << ec.message() << '\n';
+ // Carry on processing other requests.
+ return req.close(http::request_timeout, -1, ec);
+ }
   }
   else
   if (req.get.count("dir"))
@@ -292,7 +311,7 @@
     resp<< content_type("text/plain")
         << "No path specified.\n";
 
- //resp<< header("FastCGI-client", "fcgi_file_browser");
+ resp<< header("FastCGI-client", "fcgi_file_browser");
   return commit(req, resp);
 }
 
@@ -307,7 +326,7 @@
 
   // Accept requests on port 8001. You should configure your HTTP
   // server to try to connect on this port.
- acceptor a(s, 8001);
+ acceptor a(s, 8001);
 
   int ret(0);
   for (;;)
@@ -317,7 +336,7 @@
     for (;;)
     {
       a.accept(req);
- if (0 != handle_request(req))
+ if (handle_request(req))
         break;
       req.clear();
     }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk