nginx/nginx
String (ngx_str_t)
Active contributors: Maxim Dounin, Sergey Kandaurov
What it is
ngx_str_t is nginx's string type. It carries a length and a pointer; it is not null-terminated. Almost every place a function would take a const char * in normal C code, nginx takes a ngx_str_t * instead.
Definition
src/core/ngx_string.h:
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;That's it. Two fields, ~16 bytes on amd64.
Why not C strings?
Two reasons:
- Most strings come from the network. A request line is a span inside a
recv()buffer. A header value is a span inside the same buffer. nginx wants to point into those spans without copying — and there's no NUL terminator to terminate against. - NUL-injection is a class of bugs. Headers and URIs from untrusted input can contain
\0. NUL-terminated strings silently truncate at the first\0; length-prefixed strings carry the bytes faithfully and let the caller decide.
The result is faster, safer string handling at the cost of being unable to pass strings directly to most stdlib functions.
Construction
| Helper | Use |
|---|---|
ngx_string("hello") |
Compile-time literal: { 5, (u_char *) "hello" } |
ngx_str_set(&s, "hello") |
Set both fields from a literal |
ngx_str_null(&s) |
{ 0, NULL } |
ngx_null_string |
The empty ngx_str_t constant |
(ngx_str_t) { len, data } |
C99 designated initializer (less common; the macros are preferred) |
For dynamically-built strings:
ngx_str_t s;
s.data = ngx_pnalloc(pool, len);
if (s.data == NULL) return NGX_ERROR;
ngx_memcpy(s.data, src, len);
s.len = len;Comparison
| Helper | Behavior |
|---|---|
ngx_strncmp(a, b, n) |
Like strncmp. Caller must guard against length mismatches. |
ngx_strncasecmp(a, b, n) |
Case-insensitive variant. |
ngx_strcasecmp(a, b) |
NUL-aware case-insensitive (operates on C strings, rare in practice). |
ngx_strcmp(a, b) |
NUL-aware (operates on C strings). |
ngx_memcmp(a, b, n) |
Byte-equality. |
To compare two ngx_str_ts for equality, idiomatic nginx is:
if (s1->len == s2->len && ngx_strncmp(s1->data, s2->data, s1->len) == 0) {
/* equal */
}Mutation
| Helper | Behavior |
|---|---|
ngx_strlow(dst, src, n) |
Lowercase copy (ASCII only) |
ngx_strchr(s, c) |
NUL-aware (rare; usually you'd ngx_strlchr) |
ngx_strlchr(p, last, c) |
Length-bounded strchr |
ngx_cpymem(dst, src, n) |
Like memcpy but returns dst + n so you can chain copies |
ngx_copy(dst, src, n) |
Specialized fast memcpy for small fixed sizes |
Idiomatic chained copy:
u_char *p = buf;
p = ngx_copy(p, "GET ", 4);
p = ngx_copy(p, uri.data, uri.len);
p = ngx_copy(p, " HTTP/1.1\r\n", 11);Formatting
ngx_sprintf(buf, fmt, ...) and ngx_snprintf(buf, max, fmt, ...) are nginx's printf. They support a custom format-specifier set:
| Specifier | Type |
|---|---|
%V |
ngx_str_t * |
%v |
ngx_variable_value_t * |
%s |
NUL-terminated char * |
%*s |
Length + pointer (alternative to %V) |
%i, %I, %uI, %uA, %uD, %uL |
Integer types of various widths |
%f |
double |
%T |
time_t |
%M |
ngx_msec_t (milliseconds) |
%xz |
hex size_t |
%P |
ngx_pid_t |
%O |
off_t |
Stdlib printf("%s", str.data) is wrong in nginx code (might not be NUL-terminated). Always use %V with an ngx_str_t *.
ngx_sprintf returns a pointer to the byte after the last written byte — chaining-friendly.
Parsing
| Helper | Use |
|---|---|
ngx_atoi(p, n) |
Decimal ngx_int_t |
ngx_atosz(p, n) |
Decimal ssize_t |
ngx_atotm(p, n) |
Decimal time_t |
ngx_atofp(p, n, point) |
Fixed-point decimal (3 fractional digits → ms) |
ngx_hextoi(p, n) |
Hex ngx_int_t |
ngx_atoof(p, n) |
Decimal off_t |
Each returns NGX_ERROR (-1) on parse failure. Inputs are length-prefixed; no NUL needed.
Charset
u_char rather than char is the official byte type. nginx is signedness-pedantic — char is signed on most platforms and that creates surprises with the high-bit characters in HTTP headers. The convention is u_char * for raw byte spans, with explicit casts at the boundary to functions that take char *.
Hashing
| Helper | Use |
|---|---|
ngx_hash(key, c) |
Update a 32-bit FNV-1a-style hash with one byte |
ngx_hash_key(p, n) |
Hash a buffer |
ngx_hash_key_lc(p, n) |
Hash a buffer, lowercased (used for header lookup) |
ngx_hash_strlow(dst, src, n) |
Lowercase a string and return its lowercased hash |
Used by ngx_hash_t for read-only hash table lookups.
Pitfalls
%svs%V. Mixing them up is a footgun.%Vconsumes angx_str_t *;%sconsumes a NUL-terminatedchar *. The former works on most nginx data; the latter rarely does.dataisu_char *, notchar *. Cast at the boundary or use then*helpers.- Length matters. Don't assume any byte after
data[len]is valid memory. - Comparisons must include length.
ngx_strncmp(a, b, n)doesn't check thataandbare both at leastnlong — that's on you.
Cross-references
- systems/core — string + helpers in context
- how-to-contribute/patterns-and-conventions — style rules for using strings
- primitives/buffer — buffers carry the bytes that strings point into
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.