HTTP Response

HttpResponse represents an HTTP response message with status code, reason phrase, and headers. It provides methods for building and parsing HTTP responses in both client and server contexts.

HttpResponse is designed to be:

  • simple — easy status and header management
  • standard — follows HTTP/1.1 response format
  • flexible — works with clients and servers
  • efficient — minimal overhead

Basic usage

Creating responses

// libjoin.
#include <join/httpmessage.hpp>

// Create response
HttpResponse res;

// Set status and reason
res.response("200", "OK");
res.response("404", "Not Found");
res.response("500", "Internal Server Error");

Setting headers

HttpResponse res;
res.response("200", "OK");

// Add headers
res.header("Content-Type", "application/json");
res.header("Content-Length", "123");
res.header("Cache-Control", "no-cache");

Status codes

Common status codes

// Success
res.response("200", "OK");
res.response("201", "Created");
res.response("204", "No Content");

// Redirection
res.response("301", "Moved Permanently");
res.response("302", "Found");
res.response("304", "Not Modified");

// Client errors
res.response("400", "Bad Request");
res.response("401", "Unauthorized");
res.response("403", "Forbidden");
res.response("404", "Not Found");

// Server errors
res.response("500", "Internal Server Error");
res.response("502", "Bad Gateway");
res.response("503", "Service Unavailable");

Getting status

HttpResponse res;
res.response("200", "OK");

std::string status = res.status();  // "200"
std::string reason = res.reason();  // "OK"

Headers

Content headers

HttpResponse res;
res.response("200", "OK");

// Content type
res.header("Content-Type", "text/html; charset=utf-8");
res.header("Content-Type", "application/json");
res.header("Content-Type", "image/png");

// Content length
res.header("Content-Length", std::to_string(bodySize));

// Content encoding
res.header("Content-Encoding", "gzip");

Caching headers

// No caching
res.header("Cache-Control", "no-cache, no-store, must-revalidate");
res.header("Pragma", "no-cache");
res.header("Expires", "0");

// Cache for 1 hour
res.header("Cache-Control", "public, max-age=3600");

// Last modified
res.header("Last-Modified", "Wed, 21 Oct 2015 07:28:00 GMT");
res.header("ETag", "\"33a64df551425fcc55e4d42a148795d9f25f89d4\"");

CORS headers

// Allow cross-origin requests
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
res.header("Access-Control-Allow-Headers", "Content-Type, Authorization");
res.header("Access-Control-Max-Age", "86400");

Serialization

Writing response

HttpResponse res;
res.response("200", "OK");
res.header("Content-Type", "text/plain");
res.header("Content-Length", "13");

// Write to stream
std::stringstream ss;
res.writeHeaders(ss);
ss << "Hello, World!";

// Output:
// HTTP/1.1 200 OK
// Content-Type: text/plain
// Content-Length: 13
//
// Hello, World!

Reading response

HttpResponse res;

// Read from stream
if (res.readHeaders(stream) == 0)
{
    // Headers parsed successfully
    std::string status = res.status();
    std::string reason = res.reason();

    // Check content length
    size_t length = res.contentLength();
}

Common patterns

Success response

HttpResponse res;
res.response("200", "OK");
res.header("Content-Type", "application/json");

std::string json = R"({"status":"success"})";
res.header("Content-Length", std::to_string(json.size()));

stream << res;
stream << json;
stream.flush();

Error response

HttpResponse res;
res.response("404", "Not Found");
res.header("Content-Type", "text/html");

std::string html = "<html><body><h1>404 Not Found</h1></body></html>";
res.header("Content-Length", std::to_string(html.size()));

stream << res;
stream << html;
stream.flush();

Redirect response

HttpResponse res;
res.response("302", "Found");
res.header("Location", "https://example.com/new-location");
res.header("Content-Length", "0");

stream << res;
stream.flush();

JSON API response

HttpResponse res;
res.response("200", "OK");
res.header("Content-Type", "application/json");
res.header("Cache-Control", "no-cache");

std::string json = R"({
    "data": {
        "id": 123,
        "name": "Alice"
    }
})";
res.header("Content-Length", std::to_string(json.size()));

stream << res;
stream << json;
stream.flush();

Server usage

Sending responses

// In server handler
HttpResponse res;

// Success
res.response("200", "OK");
res.header("Content-Type", "text/plain");

std::string content = "Request processed successfully";
res.header("Content-Length", std::to_string(content.size()));

res.writeHeaders(stream);
stream << content;
stream.flush();

Error handling

void sendError(std::ostream& stream, const std::string& status,
               const std::string& reason)
{
    HttpResponse res;
    res.response(status, reason);
    res.header("Content-Type", "text/html");
    res.header("Connection", "close");

    std::string html = "<html><body><h1>" + status + " " +
                      reason + "</h1></body></html>";
    res.header("Content-Length", std::to_string(html.size()));

    res.writeHeaders(stream);
    stream << html;
    stream.flush();
}

Client usage

Receiving responses

// Send request
client << request;

// Receive response
HttpResponse res;
client >> res;

// Check status
if (res.status() == "200")
{
    // Success - read body
    std::string body;
    size_t length = res.contentLength();
    body.resize(length);
    client.read(&body[0], length);
}
else
{
    // Error
    std::cerr << "Error: " << res.status() << " "
              << res.reason() << "\n";
}

Helper methods

Content length

HttpResponse res;
// ... receive response ...

// Get content length from header
size_t length = res.contentLength();

if (length > 0)
{
    std::string body;
    body.resize(length);
    stream.read(&body[0], length);
}

Header checks

// Check if header exists
if (res.hasHeader("Content-Type"))
{
    std::string type = res.header("Content-Type");
}

// Get all headers
const auto& headers = res.headers();
for (const auto& [name, value] : headers)
{
    std::cout << name << ": " << value << "\n";
}

Error handling

HttpResponse res;

if (res.readHeaders(stream) == -1)
{
    std::error_code ec = join::lastError;

    if (ec == HttpErrc::BadRequest)
    {
        // Malformed response
    }
    // Handle error...
}

Best practices

Always set Content-Length

std::string body = generateBody();
res.header("Content-Length", std::to_string(body.size()));

Use appropriate status codes

// Resource created
res.response("201", "Created");

// No content to return
res.response("204", "No Content");

// Client error
res.response("400", "Bad Request");

// Not your fault
res.response("500", "Internal Server Error");

Clear and reuse

HttpResponse res;

for (const auto& item : items)
{
    res.clear();  // Reset for reuse
    res.response("200", "OK");
    // Send response...
}

Summary

FeatureSupported
Status codes✅
Headers✅
HTTP/1.1✅
Serialization✅
Content length✅
Copy/move semantics✅