Skip to content

HTTP Status Codes — C source

Searchable reference of all HTTP status codes with meaning, category, and usage notes.

This is the C implementation — the same logic the interactive tool runs, in a shareable, citable form.

/*
 * HTTP Status Codes reference — pure, deterministic data + filter.
 *
 * Language: C11 — standard library only, no third-party packages.
 * Source: CosmoDev polyglot showcase port of http-status-codes,
 *         ported from src/lib/httpStatus.ts.
 * License: display source — part of CosmoDev's polyglot tool pages.
 *
 * Pure logic — no I/O, no dynamic allocation. Behavior matches the
 * TypeScript lib: same inputs produce identical outputs.
 */
#ifndef COSMODEV_HTTP_STATUS_CODES_H
#define COSMODEV_HTTP_STATUS_CODES_H

#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>

/*
 * The five broad families an HTTP status code can belong to.
 *
 * Modeled as a plain enum rather than strings so the compiler can prove every
 * status_code carries a valid family. Tag values are the status-class digit
 * (1xx..5xx), which keeps the table self-documenting.
 */
typedef enum {
    STATUS_INFORMATIONAL = 1,
    STATUS_SUCCESS = 2,
    STATUS_REDIRECTION = 3,
    STATUS_CLIENT_ERROR = 4,
    STATUS_SERVER_ERROR = 5
} status_category;

/* Stable display name, matching the TypeScript union's string values
 * (e.g. STATUS_CLIENT_ERROR -> "Client Error"). */
const char *status_category_as_str(status_category category)
{
    switch (category) {
    case STATUS_INFORMATIONAL: return "Informational";
    case STATUS_SUCCESS:       return "Success";
    case STATUS_REDIRECTION:   return "Redirection";
    case STATUS_CLIENT_ERROR:  return "Client Error";
    case STATUS_SERVER_ERROR:  return "Server Error";
    default:                   return "Unknown";
    }
}

/*
 * Resolve a category from its display name (a trimmed span).
 *
 * Returns 1 and stores the value through `out` on success; returns 0 when the
 * name is unknown. The filter turns 0 into an empty result, exactly as the
 * TypeScript version does.
 */
int status_category_from_str(const char *name, size_t name_len, status_category *out)
{
    int cat;
    for (cat = STATUS_INFORMATIONAL; cat <= STATUS_SERVER_ERROR; cat++) {
        const char *display = status_category_as_str((status_category)cat);
        size_t display_len = strlen(display);
        if (display_len == name_len && memcmp(display, name, name_len) == 0) {
            if (out != NULL)
                *out = (status_category)cat;
            return 1;
        }
    }
    return 0;
}

/* A single HTTP status code entry.
 *
 * All members point at static storage; the table below is never mutated. */
typedef struct {
    int code;
    const char *reason;
    status_category category;
    const char *description;
} status_code;

/* Standard + widely-implemented HTTP status codes across 1xx–5xx.
 *
 * A static const array — the table is constant. Order is grouped by category,
 * ascending within each group. */
static const status_code STATUS_CODES[] = {
    /* --- 1xx Informational --- */
    { 100, "Continue", STATUS_INFORMATIONAL, "The server has received the request headers and the client should proceed to send the request body." },
    { 101, "Switching Protocols", STATUS_INFORMATIONAL, "The requester has asked the server to switch protocols and the server has agreed to do so." },
    { 103, "Early Hints", STATUS_INFORMATIONAL, "Used to return some response headers before the final HTTP message so the browser can start preloading resources." },

    /* --- 2xx Success --- */
    { 200, "OK", STATUS_SUCCESS, "Standard response for a successful HTTP request." },
    { 201, "Created", STATUS_SUCCESS, "The request succeeded and a new resource was created." },
    { 202, "Accepted", STATUS_SUCCESS, "The request has been accepted for processing but is not yet complete." },
    { 203, "Non-Authoritative Information", STATUS_SUCCESS, "The returned metadata originated from a local or third-party copy rather than the origin server." },
    { 204, "No Content", STATUS_SUCCESS, "The server processed the request successfully but is not returning any content." },
    { 205, "Reset Content", STATUS_SUCCESS, "The server asks the client to reset the document view that sent the request." },
    { 206, "Partial Content", STATUS_SUCCESS, "The server is delivering only part of the resource because the client requested a byte range." },
    { 207, "Multi-Status", STATUS_SUCCESS, "WebDAV: conveys information about multiple resources in a single XML response." },
    { 208, "Already Reported", STATUS_SUCCESS, "WebDAV: the members of a DAV binding have already been enumerated in a previous reply." },
    { 226, "IM Used", STATUS_SUCCESS, "The server fulfilled a GET request using an instance-manipulation applied to the current instance." },

    /* --- 3xx Redirection --- */
    { 300, "Multiple Choices", STATUS_REDIRECTION, "The request has more than one possible response; the user agent can choose among them." },
    { 301, "Moved Permanently", STATUS_REDIRECTION, "This and all future requests should be directed to the given URL." },
    { 302, "Found", STATUS_REDIRECTION, "The resource resides temporarily under a different URL; the method may be changed to GET." },
    { 303, "See Other", STATUS_REDIRECTION, "The response to the request can be found under another URI using a GET request." },
    { 304, "Not Modified", STATUS_REDIRECTION, "The resource has not been modified since the version specified by the request headers." },
    { 305, "Use Proxy", STATUS_REDIRECTION, "The requested resource is available only through a proxy (deprecated)." },
    { 306, "Switch Proxy", STATUS_REDIRECTION, "No longer used; originally meant subsequent requests should use a specified proxy." },
    { 307, "Temporary Redirect", STATUS_REDIRECTION, "The request should be repeated with another URL; the request method must not change." },
    { 308, "Permanent Redirect", STATUS_REDIRECTION, "This and all future requests should use another URL; the request method must not change." },

    /* --- 4xx Client Error --- */
    { 400, "Bad Request", STATUS_CLIENT_ERROR, "The server cannot process the request due to a client error such as malformed syntax." },
    { 401, "Unauthorized", STATUS_CLIENT_ERROR, "Authentication is required and has either failed or not been provided." },
    { 402, "Payment Required", STATUS_CLIENT_ERROR, "Reserved for future use; sometimes used for paywalled resources." },
    { 403, "Forbidden", STATUS_CLIENT_ERROR, "The server understood the request but refuses to authorize it." },
    { 404, "Not Found", STATUS_CLIENT_ERROR, "The requested resource could not be found on the server." },
    { 405, "Method Not Allowed", STATUS_CLIENT_ERROR, "The request method is not supported for the requested resource." },
    { 406, "Not Acceptable", STATUS_CLIENT_ERROR, "The requested resource can only generate content not acceptable per the Accept headers." },
    { 407, "Proxy Authentication Required", STATUS_CLIENT_ERROR, "The client must first authenticate itself with the proxy." },
    { 408, "Request Timeout", STATUS_CLIENT_ERROR, "The server timed out waiting for the client to send the request." },
    { 409, "Conflict", STATUS_CLIENT_ERROR, "The request could not be processed because of a conflict with the current state of the resource." },
    { 410, "Gone", STATUS_CLIENT_ERROR, "The resource is no longer available and will not be available again." },
    { 411, "Length Required", STATUS_CLIENT_ERROR, "The request did not specify the length of its content, which is required by the resource." },
    { 412, "Precondition Failed", STATUS_CLIENT_ERROR, "The server does not meet one of the preconditions given in the request headers." },
    { 413, "Content Too Large", STATUS_CLIENT_ERROR, "The request payload is larger than the server is willing or able to process." },
    { 414, "URI Too Long", STATUS_CLIENT_ERROR, "The URI provided was too long for the server to process." },
    { 415, "Unsupported Media Type", STATUS_CLIENT_ERROR, "The request uses a media type the server does not support for the resource." },
    { 416, "Range Not Satisfiable", STATUS_CLIENT_ERROR, "The portion of the resource requested in the Range header cannot be supplied by the server." },
    { 417, "Expectation Failed", STATUS_CLIENT_ERROR, "The server cannot meet the requirements of the Expect request header field." },
    { 418, "I'm a Teapot", STATUS_CLIENT_ERROR, "RFC 2324 joke status: the server refuses to brew coffee because it is, permanently, a teapot." },
    { 421, "Misdirected Request", STATUS_CLIENT_ERROR, "The request was directed at a server that is not able to produce a response." },
    { 422, "Unprocessable Content", STATUS_CLIENT_ERROR, "The server understands the content type and syntax but cannot process the contained instructions (WebDAV)." },
    { 423, "Locked", STATUS_CLIENT_ERROR, "WebDAV: the source or destination resource of the method is locked." },
    { 424, "Failed Dependency", STATUS_CLIENT_ERROR, "WebDAV: the method could not be performed because the requested action depended on another action that failed." },
    { 425, "Too Early", STATUS_CLIENT_ERROR, "The server is unwilling to risk processing a request that might be a replay." },
    { 428, "Precondition Required", STATUS_CLIENT_ERROR, "The origin server requires the request to be conditional." },
    { 429, "Too Many Requests", STATUS_CLIENT_ERROR, "The user has sent too many requests in a given time (rate limiting)." },
    { 431, "Request Header Fields Too Large", STATUS_CLIENT_ERROR, "The server is unwilling to process the request because its header fields are too large." },
    { 451, "Unavailable For Legal Reasons", STATUS_CLIENT_ERROR, "The resource is unavailable due to legal demands such as government censorship or a takedown." },

    /* --- 5xx Server Error --- */
    { 500, "Internal Server Error", STATUS_SERVER_ERROR, "A generic error message: the server encountered an unexpected condition." },
    { 501, "Not Implemented", STATUS_SERVER_ERROR, "The server does not support the functionality required to fulfill the request." },
    { 502, "Bad Gateway", STATUS_SERVER_ERROR, "The server, acting as a gateway, received an invalid response from an upstream server." },
    { 503, "Service Unavailable", STATUS_SERVER_ERROR, "The server is currently unavailable, typically because it is overloaded or down for maintenance." },
    { 504, "Gateway Timeout", STATUS_SERVER_ERROR, "The server, acting as a gateway, timed out waiting for an upstream response." },
    { 505, "HTTP Version Not Supported", STATUS_SERVER_ERROR, "The server does not support the HTTP protocol version used in the request." },
    { 506, "Variant Also Negotiates", STATUS_SERVER_ERROR, "Transparent content negotiation for the request resulted in a circular reference." },
    { 507, "Insufficient Storage", STATUS_SERVER_ERROR, "WebDAV: the server is unable to store the representation needed to complete the request." },
    { 508, "Loop Detected", STATUS_SERVER_ERROR, "WebDAV: the server detected an infinite loop while processing the request." },
    { 510, "Not Extended", STATUS_SERVER_ERROR, "Further extensions to the request are required for the server to fulfill it." },
    { 511, "Network Authentication Required", STATUS_SERVER_ERROR, "The client must authenticate to gain network access, as with a captive portal." }
};

#define STATUS_CODES_LEN (sizeof STATUS_CODES / sizeof STATUS_CODES[0])

/* Lowercase an ASCII byte. */
static unsigned char ascii_lower(unsigned char c)
{
    return (c >= 'A' && c <= 'Z') ? (unsigned char)(c - 'A' + 'a') : c;
}

/* Case-insensitive substring search over an ASCII span.
 *
 * Standard C has no strcasestr, so here is a small self-contained one; both
 * sides are lowercased on the fly, so no buffer is needed for the needle. */
static int ci_contains(const char *haystack, size_t haystack_len,
                       const char *needle, size_t needle_len)
{
    size_t i;
    if (needle_len == 0)
        return 1;
    if (haystack_len < needle_len)
        return 0;
    for (i = 0; i + needle_len <= haystack_len; i++) {
        size_t j = 0;
        while (j < needle_len
               && ascii_lower((unsigned char)haystack[i + j]) == ascii_lower((unsigned char)needle[j]))
            j++;
        if (j == needle_len)
            return 1;
    }
    return 0;
}

/* Trim ASCII whitespace from both ends of a NUL-terminated string.
 *
 * Sets *start past the leading whitespace and returns the span length. */
static size_t trim_span(const char *s, const char **start)
{
    const char *end;
    while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
        s++;
    *start = s;
    end = s;
    while (*end != '\0')
        end++;
    while (end > s
           && (end[-1] == ' ' || end[-1] == '\t' || end[-1] == '\n' || end[-1] == '\r'))
        end--;
    return (size_t)(end - s);
}

/*
 * Filter status codes by a free-text query and an optional category.
 *
 * `query` is matched case-insensitively against the numeric code (as a decimal
 * string), the reason phrase, and the description. An empty/whitespace query
 * returns every code in the pool. `category` restricts the pool first: NULL or
 * "" means "no restriction"; an unknown name yields zero results — matching
 * the TypeScript semantics.
 *
 * Matches are written as pointers into `codes` (original order preserved)
 * until `cap` is reached; the total number of matches is returned, so a caller
 * can call once with out == NULL / cap == 0 to size its buffer first.
 */
size_t filter_codes(const char *query,
                    const status_code *codes,
                    size_t codes_len,
                    const char *category,
                    const status_code **out,
                    size_t cap)
{
    status_category cat;
    int have_cat = 0;
    const char *needle;
    size_t needle_len;
    size_t matched = 0;
    size_t written = 0;
    size_t i;

    /* Resolve the category: NULL/blank -> no filter; a name that does not
     * parse as a known family -> nothing can match, so short-circuit. */
    if (category != NULL) {
        const char *cat_start;
        size_t cat_len = trim_span(category, &cat_start);
        if (cat_len != 0) {
            if (!status_category_from_str(cat_start, cat_len, &cat))
                return 0;
            have_cat = 1;
        }
    }

    needle_len = trim_span(query, &needle);
    if (needle_len == 0)
        needle = NULL;

    for (i = 0; i < codes_len; i++) {
        const status_code *entry = &codes[i];
        if (have_cat && entry->category != cat)
            continue;
        if (needle != NULL) {
            /* The code is matched against its decimal string form, so "40"
             * hits 404, 405, ... */
            char code_str[8];
            int code_len = snprintf(code_str, sizeof code_str, "%d", entry->code);
            if (!ci_contains(code_str, (size_t)code_len, needle, needle_len)
                && !ci_contains(entry->reason, strlen(entry->reason), needle, needle_len)
                && !ci_contains(entry->description, strlen(entry->description), needle, needle_len))
                continue;
        }
        if (out != NULL && written < cap) {
            out[written] = entry;
            written++;
        }
        matched++;
    }
    return matched;
}

#endif /* COSMODEV_HTTP_STATUS_CODES_H */

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →