@@ -838,6 +838,50 @@ struct Response {
838838 std::string file_content_content_type_;
839839};
840840
841+ enum class Error {
842+ Success = 0 ,
843+ Unknown,
844+ Connection,
845+ BindIPAddress,
846+ Read,
847+ Write,
848+ ExceedRedirectCount,
849+ Canceled,
850+ SSLConnection,
851+ SSLLoadingCerts,
852+ SSLServerVerification,
853+ SSLServerHostnameVerification,
854+ UnsupportedMultipartBoundaryChars,
855+ Compression,
856+ ConnectionTimeout,
857+ ProxyConnection,
858+ ConnectionClosed,
859+ Timeout,
860+ ResourceExhaustion,
861+ TooManyFormDataFiles,
862+ ExceedMaxPayloadSize,
863+ ExceedUriMaxLength,
864+ ExceedMaxSocketDescriptorCount,
865+ InvalidRequestLine,
866+ InvalidHTTPMethod,
867+ InvalidHTTPVersion,
868+ InvalidHeaders,
869+ MultipartParsing,
870+ OpenFile,
871+ Listen,
872+ GetSockName,
873+ UnsupportedAddressFamily,
874+ HTTPParsing,
875+ InvalidRangeHeader,
876+
877+ // For internal use only
878+ SSLPeerCouldBeClosed_,
879+ };
880+
881+ std::string to_string (Error error);
882+
883+ std::ostream &operator <<(std::ostream &os, const Error &obj);
884+
841885class Stream {
842886public:
843887 virtual ~Stream () = default ;
@@ -856,6 +900,11 @@ class Stream {
856900
857901 ssize_t write (const char *ptr);
858902 ssize_t write (const std::string &s);
903+
904+ Error get_error () const { return error_; }
905+
906+ protected:
907+ Error error_ = Error::Success;
859908};
860909
861910class TaskQueue {
@@ -1292,48 +1341,6 @@ class Server {
12921341 detail::write_headers;
12931342};
12941343
1295- enum class Error {
1296- Success = 0 ,
1297- Unknown,
1298- Connection,
1299- BindIPAddress,
1300- Read,
1301- Write,
1302- ExceedRedirectCount,
1303- Canceled,
1304- SSLConnection,
1305- SSLLoadingCerts,
1306- SSLServerVerification,
1307- SSLServerHostnameVerification,
1308- UnsupportedMultipartBoundaryChars,
1309- Compression,
1310- ConnectionTimeout,
1311- ProxyConnection,
1312- ResourceExhaustion,
1313- TooManyFormDataFiles,
1314- ExceedMaxPayloadSize,
1315- ExceedUriMaxLength,
1316- ExceedMaxSocketDescriptorCount,
1317- InvalidRequestLine,
1318- InvalidHTTPMethod,
1319- InvalidHTTPVersion,
1320- InvalidHeaders,
1321- MultipartParsing,
1322- OpenFile,
1323- Listen,
1324- GetSockName,
1325- UnsupportedAddressFamily,
1326- HTTPParsing,
1327- InvalidRangeHeader,
1328-
1329- // For internal use only
1330- SSLPeerCouldBeClosed_,
1331- };
1332-
1333- std::string to_string (Error error);
1334-
1335- std::ostream &operator <<(std::ostream &os, const Error &obj);
1336-
13371344class Result {
13381345public:
13391346 Result () = default ;
@@ -2437,6 +2444,8 @@ inline std::string to_string(const Error error) {
24372444 case Error::Compression: return " Compression failed" ;
24382445 case Error::ConnectionTimeout: return " Connection timed out" ;
24392446 case Error::ProxyConnection: return " Proxy connection failed" ;
2447+ case Error::ConnectionClosed: return " Connection closed by server" ;
2448+ case Error::Timeout: return " Read timeout" ;
24402449 case Error::ResourceExhaustion: return " Resource exhaustion" ;
24412450 case Error::TooManyFormDataFiles: return " Too many form data files" ;
24422451 case Error::ExceedMaxPayloadSize: return " Exceeded maximum payload size" ;
@@ -7273,13 +7282,15 @@ inline ssize_t detail::BodyReader::read(char *buf, size_t len) {
72737282 auto n = stream->read (buf, to_read);
72747283
72757284 if (n < 0 ) {
7276- last_error = Error::Read;
7285+ last_error = stream->get_error ();
7286+ if (last_error == Error::Success) { last_error = Error::Read; }
72777287 eof = true ;
72787288 return n;
72797289 }
72807290 if (n == 0 ) {
72817291 // Unexpected EOF before content_length
7282- last_error = Error::Read;
7292+ last_error = stream->get_error ();
7293+ if (last_error == Error::Success) { last_error = Error::Read; }
72837294 eof = true ;
72847295 return 0 ;
72857296 }
@@ -7296,7 +7307,8 @@ inline ssize_t detail::BodyReader::read(char *buf, size_t len) {
72967307 size_t chunk_total = 0 ;
72977308 auto n = chunked_decoder->read_payload (buf, len, chunk_offset, chunk_total);
72987309 if (n < 0 ) {
7299- last_error = Error::Read;
7310+ last_error = stream->get_error ();
7311+ if (last_error == Error::Success) { last_error = Error::Read; }
73007312 eof = true ;
73017313 return n;
73027314 }
@@ -7387,7 +7399,10 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
73877399 }
73887400 }
73897401
7390- if (!wait_readable ()) { return -1 ; }
7402+ if (!wait_readable ()) {
7403+ error_ = Error::Timeout;
7404+ return -1 ;
7405+ }
73917406
73927407 read_buff_off_ = 0 ;
73937408 read_buff_content_size_ = 0 ;
@@ -7396,6 +7411,11 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
73967411 auto n = read_socket (sock_, read_buff_.data (), read_buff_size_,
73977412 CPPHTTPLIB_RECV_FLAGS);
73987413 if (n <= 0 ) {
7414+ if (n == 0 ) {
7415+ error_ = Error::ConnectionClosed;
7416+ } else {
7417+ error_ = Error::Read;
7418+ }
73997419 return n;
74007420 } else if (n <= static_cast <ssize_t >(size)) {
74017421 memcpy (ptr, read_buff_.data (), static_cast <size_t >(n));
@@ -7407,7 +7427,15 @@ inline ssize_t SocketStream::read(char *ptr, size_t size) {
74077427 return static_cast <ssize_t >(size);
74087428 }
74097429 } else {
7410- return read_socket (sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
7430+ auto n = read_socket (sock_, ptr, size, CPPHTTPLIB_RECV_FLAGS);
7431+ if (n <= 0 ) {
7432+ if (n == 0 ) {
7433+ error_ = Error::ConnectionClosed;
7434+ } else {
7435+ error_ = Error::Read;
7436+ }
7437+ }
7438+ return n;
74117439 }
74127440}
74137441
@@ -11435,7 +11463,9 @@ inline bool SSLSocketStream::wait_writable() const {
1143511463
1143611464inline ssize_t SSLSocketStream::read (char *ptr, size_t size) {
1143711465 if (SSL_pending (ssl_) > 0 ) {
11438- return SSL_read (ssl_, ptr, static_cast <int >(size));
11466+ auto ret = SSL_read (ssl_, ptr, static_cast <int >(size));
11467+ if (ret == 0 ) { error_ = Error::ConnectionClosed; }
11468+ return ret;
1143911469 } else if (wait_readable ()) {
1144011470 auto ret = SSL_read (ssl_, ptr, static_cast <int >(size));
1144111471 if (ret < 0 ) {
@@ -11460,9 +11490,12 @@ inline ssize_t SSLSocketStream::read(char *ptr, size_t size) {
1146011490 }
1146111491 }
1146211492 assert (ret < 0 );
11493+ } else if (ret == 0 ) {
11494+ error_ = Error::ConnectionClosed;
1146311495 }
1146411496 return ret;
1146511497 } else {
11498+ error_ = Error::Timeout;
1146611499 return -1 ;
1146711500 }
1146811501}
0 commit comments