. "$BST_LIB" # http-parser is the nodejs streaming HTTP request/response parser -- 2568 lines # of C behind fourteen entry points and one 32-byte caller-owned struct. It is the # HTTP-message parser this image did not have: libinih, iniparser and minini read # .INI, libxml2 reads XML, jansson / json-c / libfastjson / cjson read JSON, # uriparser reads URIs, and none of them parses a protocol stream that arrives in # pieces. There is no CLI and no consumer on this image, so the whole shipped # payload is /usr/include/http_parser.h (-dev) and /usr/lib/libhttp_parser.a # (-staticdev). # # --------------------------------------------------------------------------- # WHY THIS SUITE RUNS A PROBE INSTEAD OF STOPPING AT PAYLOAD SHAPE # # BRINTOS-217 is why: oniguruma COMPILED and PACKAGED perfectly on this arm and # then returned silently wrong offsets to every caller, so a payload-only suite # would have gone green on the exact defect the port existed to find. # # http-parser's exposure is the widest on this Epic so far, and it is all # substrate rather than library. The library allocates nothing, issues no syscall # and holds no state outside the caller's struct, so what is actually under test # here is the platform: # # run-req-* run-resp-* http_parser_execute drives TEN caller-supplied function # pointers out of a const http_parser_settings -- an # indirect call made from a coroutinized frame -- and # hands each data callback a (pointer, length) pair AIMED # INTO THE CALLER'S OWN INPUT BUFFER. minini's ini_browse # was this Epic's first callback API and had one; this is # ten, in one table, driven from a state machine. # run-scatter-* the library's headline claim is that it can be # interrupted between ANY two bytes. The probe feeds the # same request ONE BYTE PER CALL -- 74 re-entries, each # resuming from a bitfield-packed `state` -- and asserts # the callback sequence and every field's text against # THE SINGLE-SHOT RUN'S OWN RESULT. Steps of 3 and 7 # split mid-token, mid-CRLF and mid-chunk-size. # run-clen-* content_length is uint64_t, i64 on wasm32, asserted at # 2^32, at 2^53+1, at 2^53+1 fed one digit per call, and # at upstream's overflow rejection. # run-url-* http_parser_parse_url is a SECOND state machine writing # uint16_t off/len pairs into a caller-owned struct; each # field is read back OUT of the caller's buffer at the # offset the library wrote, so a wrong offset shows as # wrong TEXT and not as a silent mask difference. # run-str-* static const char *const tables reached by enum index # -- read-only data through a table, a different access # path from any of the parser code above. # # EVERY EXPECTED VALUE IS THE VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL RELEASE # PRODUCES. The probe compares each value internally and prints it on both the OK # and the FAIL path, so a target run can be diffed against the native control line # by line rather than compared by tally -- which native-byte-identical below does, # on target, with cmp(1). # # THE SHIPPED ARCHIVE IS THE NON-STRICT BUILD, and that is upstream's choice # rather than this port's: `package` builds http_parser.o with CPPFLAGS_FAST = # -DHTTP_PARSER_STRICT=0. run-lenient-* and run-strict-* assert the consequence # directly, so a future recipe that switched to the debug object fails a case # instead of silently changing behaviour. # # NOTHING HERE IS WORKED AROUND AND NO CASE IS RELAXED. Eleven expectations of # mine were wrong and the native control caught every one before it could ship as # a red blaming the platform; they are corrected above, not accommodated. # # The suite uses builtin `case` matching over variables read ONCE, never # `check_out ... cat` per case: on this runtime the forking is the cost rather # than the work, and the cjson suite next door was killed by the runner's # per-suite bound at 156 cases written the other way. This suite is 250 cases and # forks four times in total -- two greps over the archive, the probe, and the # on-target byte-diff against the native control. # --------------------------------------------------------------------------- hdr=/usr/include/http_parser.h lib=/usr/lib/libhttp_parser.a nl=' ' # hasfile -- ok iff is a non-empty regular file. # has -- ok iff contains the literal . # hasline -- ok iff carries as a WHOLE line. # Substring matching would let http_parser_init # satisfy a lookup for http_parser_init_foo. hasfile() { if [ -s "$2" ]; then bst_ok "$1"; else bst_notok "$1" "absent or empty: $2"; fi; } has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) bst_notok "$1" "not found: $2" ;; esac; } hasline() { case "$nl$3$nl" in *"$nl$2$nl"*) bst_ok "$1" ;; *) bst_notok "$1" "not in archive: $2" ;; esac; } # An image built without http-parser is a coverage gap, not a failure: skip once # and stop rather than reporting 250 reds for an absent package. if [ ! -s "$lib" ]; then bst_skip http-parser/present "libhttp_parser.a not installed on this image" exit 0 fi bst_ok http-parser/present # --- the shipped payload ----------------------------------------------------- # Upstream's install target puts the one header straight into ${includedir} # rather than a per-package subdirectory, and the bbappend keeps that exactly. hasfile http-parser/header "$hdr" hasfile http-parser/archive "$lib" # There is deliberately no http-parser/no-shared-object case: shared objects are # refused distro-wide on this arm, so an absent libhttp_parser.so is the distro's # property and not this port's, and every sibling library would assert it too. # --- what the installed header must carry ------------------------------------ # These are the values every runtime case below depends on, so a header change # should fail loudly here rather than shift every number underneath it. hdrtext=$(cat "$hdr" 2>/dev/null) has http-parser/hdr-version-major "define HTTP_PARSER_VERSION_MAJOR 2" "$hdrtext" has http-parser/hdr-version-minor "define HTTP_PARSER_VERSION_MINOR 9" "$hdrtext" has http-parser/hdr-version-patch "define HTTP_PARSER_VERSION_PATCH 4" "$hdrtext" # the ten callback slots, in the order http_parser_execute fires them has http-parser/hdr-cb-message-begin "http_cb on_message_begin" "$hdrtext" has http-parser/hdr-cb-url "http_data_cb on_url" "$hdrtext" has http-parser/hdr-cb-status "http_data_cb on_status" "$hdrtext" has http-parser/hdr-cb-header-field "http_data_cb on_header_field" "$hdrtext" has http-parser/hdr-cb-header-value "http_data_cb on_header_value" "$hdrtext" has http-parser/hdr-cb-headers-complete "http_cb on_headers_complete" "$hdrtext" has http-parser/hdr-cb-body "http_data_cb on_body" "$hdrtext" has http-parser/hdr-cb-message-complete "http_cb on_message_complete" "$hdrtext" has http-parser/hdr-cb-chunk-header "http_cb on_chunk_header" "$hdrtext" has http-parser/hdr-cb-chunk-complete "http_cb on_chunk_complete" "$hdrtext" # the two callback TYPES: on_url/on_status/on_header_* carry a length, the others # do not, and mixing them up is a whole-API type error rather than one case. has http-parser/hdr-typedef-cb "typedef int (*http_cb) (http_parser*)" "$hdrtext" has http-parser/hdr-typedef-data-cb "typedef int (*http_data_cb) (http_parser*, const char *at, size_t length)" "$hdrtext" # the struct members every callback writes through, and the 64-bit one has http-parser/hdr-content-length "uint64_t content_length" "$hdrtext" has http-parser/hdr-nread "uint32_t nread" "$hdrtext" has http-parser/hdr-upgrade-bit "unsigned int upgrade : 1" "$hdrtext" has http-parser/hdr-status-code "unsigned int status_code : 16" "$hdrtext" has http-parser/hdr-url-field-data "} field_data[UF_MAX]" "$hdrtext" has http-parser/hdr-errno-macro "define HTTP_PARSER_ERRNO(p)" "$hdrtext" # --- symbol completeness, derived from the INSTALLED header ------------------- # Every http_* function the installed header declares must be a real symbol of the # installed archive, so a partial compile, a visibility mistake or a # header/library skew all fail this. The list is DERIVED from the header rather # than written here, so it survives a version bump; the count is pinned at 14 and # the entry points the runtime cases actually drive are spot-checked by name, so # an empty derivation cannot make the loop vacuously green. arcsyms=$(grep -ao 'http_[A-Za-z0-9_]*' "$lib" 2>/dev/null | sort -u) hdrsyms=$(grep -v '^[[:space:]]*#' "$hdr" 2>/dev/null \ | grep -oE '\bhttp_[A-Za-z0-9_]*\(' | sed 's/(//' | sort -u) nsym=0 nmiss=0 missing="" for f in $hdrsyms; do nsym=$((nsym + 1)) case "$nl$arcsyms$nl" in *"$nl$f$nl"*) ;; *) nmiss=$((nmiss + 1)); missing="$missing $f" ;; esac done if [ "$nmiss" -eq 0 ]; then bst_ok http-parser/symbols-complete else bst_notok http-parser/symbols-complete "$nmiss missing:$missing" fi check_eq http-parser/symbols-count 14 "$nsym" hasline http-parser/sym-execute http_parser_execute "$arcsyms" hasline http-parser/sym-init http_parser_init "$arcsyms" hasline http-parser/sym-settings-init http_parser_settings_init "$arcsyms" hasline http-parser/sym-parse-url http_parser_parse_url "$arcsyms" hasline http-parser/sym-url-init http_parser_url_init "$arcsyms" hasline http-parser/sym-pause http_parser_pause "$arcsyms" hasline http-parser/sym-body-final http_body_is_final "$arcsyms" hasline http-parser/sym-keep-alive http_should_keep_alive "$arcsyms" hasline http-parser/sym-method-str http_method_str "$arcsyms" hasline http-parser/sym-status-str http_status_str "$arcsyms" hasline http-parser/sym-errno-name http_errno_name "$arcsyms" hasline http-parser/sym-errno-desc http_errno_description "$arcsyms" hasline http-parser/sym-max-hdr-size http_parser_set_max_header_size "$arcsyms" hasline http-parser/sym-version http_parser_version "$arcsyms" # --- the library RUNNING, via the cross-linked probe ------------------------- # data/http-parser-probe is src/http_parser_probe.c cross-linked with wasmcc-glibc # against THE VERY ARCHIVE THAT SHIPS (/usr/lib/libhttp_parser.a), staged to # $TMPDIR and run here. probe=${TMPDIR:-/tmp}/bst-http-parser-probe.$$ if cp "$BST_DATA/http-parser-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then # The probe is run ONCE and its exit status kept, rather than re-run for the rc # case: on this runtime a multi-MB wasm module's start-up dominates the whole # suite's cost. out=$("$probe" 2>&1); prc=$? # identity and layout. sizeof(struct http_parser_url) holds only uint16_t so it # is 32 on both arms; sizeof(http_parser) is 32 on both TOO, because its # uint64_t content_length forces 8-byte struct alignment and the 4-byte tail # pointer is padded up to what the 8-byte one occupies natively. Both are # portable ABI facts, and if either diverged every case below would be # meaningless. has http-parser/run-version-major "HP-version-major OK" "$out" has http-parser/run-version-minor "HP-version-minor OK" "$out" has http-parser/run-version-patch "HP-version-patch OK" "$out" has http-parser/run-sizeof-url "HP-sizeof-url OK" "$out" has http-parser/run-uf-max "HP-uf-max OK" "$out" has http-parser/run-sizeof-parser "HP-sizeof-parser OK" "$out" # the init contract: http_parser_init must clear a struct full of residue while # PRESERVING the caller's data pointer, and http_parser_settings_init must zero # all ten callback slots -- a slot left with residue is an indirect call to # garbage on the very first message. has http-parser/run-init-type "HP-init-type OK" "$out" has http-parser/run-init-errno "HP-init-errno OK" "$out" has http-parser/run-init-nread "HP-init-nread OK" "$out" has http-parser/run-init-clen "HP-init-clen OK" "$out" has http-parser/run-init-upgrade "HP-init-upgrade OK" "$out" has http-parser/run-init-keeps-data "HP-init-keeps-data OK" "$out" has http-parser/run-init-type-response "HP-init-type-response OK" "$out" has http-parser/run-settings-init-zeroed "HP-settings-init-zeroed OK" "$out" # A WHOLE REQUEST, ONE SHOT. This is the group the port exists to prove: ten # indirect calls out of a const dispatch table, each handed a (pointer, length) # pair aimed into the caller's own input buffer. req-seq is the callback ORDER, # req-hdrs the three field/value pairs reassembled from the fragments the # callbacks delivered, req-url and req-body the text at the offsets given. has http-parser/run-req-consumed "HP-req-consumed OK" "$out" has http-parser/run-req-errno "HP-req-errno OK" "$out" has http-parser/run-req-method "HP-req-method OK" "$out" has http-parser/run-req-method-str "HP-req-method-str OK" "$out" has http-parser/run-req-major "HP-req-major OK" "$out" has http-parser/run-req-minor "HP-req-minor OK" "$out" has http-parser/run-req-upgrade "HP-req-upgrade OK" "$out" has http-parser/run-req-keepalive "HP-req-keepalive OK" "$out" has http-parser/run-req-seq "HP-req-seq OK" "$out" has http-parser/run-req-url "HP-req-url OK" "$out" has http-parser/run-req-hdrs "HP-req-hdrs OK" "$out" has http-parser/run-req-body "HP-req-body OK" "$out" has http-parser/run-req-n-mb "HP-req-n-mb OK" "$out" has http-parser/run-req-n-hc "HP-req-n-hc OK" "$out" has http-parser/run-req-n-mc "HP-req-n-mc OK" "$out" has http-parser/run-req-n-chh "HP-req-n-chh OK" "$out" has http-parser/run-req-body-final "HP-req-body-final OK" "$out" has http-parser/run-req-status-empty "HP-req-status-empty OK" "$out" has http-parser/run-req-clen-drained "HP-req-clen-drained OK" "$out" # THE SAME REQUEST, ONE BYTE PER http_parser_execute CALL -- 74 re-entries into # a state machine that resumes from a bitfield-packed `state` each time. Every # expectation here is the SINGLE-SHOT run's own result, captured inside the # probe, so this compares the parser against itself rather than against a # literal that could be wrong. Steps of 3 and 7 split on the awkward boundaries # a 1-byte step never produces: mid-token, mid-CRLF, mid-chunk-size. has http-parser/run-scatter1-consumed "HP-scatter1-consumed OK" "$out" has http-parser/run-scatter1-calls "HP-scatter1-calls OK" "$out" has http-parser/run-scatter1-errno "HP-scatter1-errno OK" "$out" has http-parser/run-scatter1-method "HP-scatter1-method OK" "$out" has http-parser/run-scatter1-seq "HP-scatter1-seq OK" "$out" has http-parser/run-scatter1-url "HP-scatter1-url OK" "$out" has http-parser/run-scatter1-hdrs "HP-scatter1-hdrs OK" "$out" has http-parser/run-scatter1-body "HP-scatter1-body OK" "$out" has http-parser/run-scatter1-n-mc "HP-scatter1-n-mc OK" "$out" has http-parser/run-scatter3-consumed "HP-scatter3-consumed OK" "$out" has http-parser/run-scatter3-seq "HP-scatter3-seq OK" "$out" has http-parser/run-scatter3-url "HP-scatter3-url OK" "$out" has http-parser/run-scatter3-hdrs "HP-scatter3-hdrs OK" "$out" has http-parser/run-scatter3-body "HP-scatter3-body OK" "$out" has http-parser/run-scatter7-consumed "HP-scatter7-consumed OK" "$out" has http-parser/run-scatter7-seq "HP-scatter7-seq OK" "$out" has http-parser/run-scatter7-url "HP-scatter7-url OK" "$out" has http-parser/run-scatter7-hdrs "HP-scatter7-hdrs OK" "$out" has http-parser/run-scatter7-body "HP-scatter7-body OK" "$out" # a whole response: the status line, the reason phrase through on_status (a # callback the request path never fires), and the same one-byte-at-a-time run. has http-parser/run-resp-consumed "HP-resp-consumed OK" "$out" has http-parser/run-resp-errno "HP-resp-errno OK" "$out" has http-parser/run-resp-status "HP-resp-status OK" "$out" has http-parser/run-resp-status-text "HP-resp-status-text OK" "$out" has http-parser/run-resp-seq "HP-resp-seq OK" "$out" has http-parser/run-resp-hdrs "HP-resp-hdrs OK" "$out" has http-parser/run-resp-body "HP-resp-body OK" "$out" has http-parser/run-resp-keepalive "HP-resp-keepalive OK" "$out" has http-parser/run-resp-url-empty "HP-resp-url-empty OK" "$out" has http-parser/run-resp-scatter-consumed "HP-resp-scatter-consumed OK" "$out" has http-parser/run-resp-scatter-seq "HP-resp-scatter-seq OK" "$out" has http-parser/run-resp-scatter-status "HP-resp-scatter-status OK" "$out" has http-parser/run-resp-scatter-body "HP-resp-scatter-body OK" "$out" # CHUNKED TRANSFER ENCODING -- the shape with the most loop-carried state. # on_chunk_header/on_chunk_complete bracket each chunk, the chunk size is a hex # accumulator carried ACROSS execute calls, and http_body_is_final is false # inside a non-final chunk. The scatter run re-enters the size scanner one hex # digit at a time. has http-parser/run-chunk-consumed "HP-chunk-consumed OK" "$out" has http-parser/run-chunk-errno "HP-chunk-errno OK" "$out" has http-parser/run-chunk-status "HP-chunk-status OK" "$out" has http-parser/run-chunk-seq "HP-chunk-seq OK" "$out" has http-parser/run-chunk-body "HP-chunk-body OK" "$out" has http-parser/run-chunk-sizes "HP-chunk-sizes OK" "$out" has http-parser/run-chunk-n-chh "HP-chunk-n-chh OK" "$out" has http-parser/run-chunk-n-chc "HP-chunk-n-chc OK" "$out" has http-parser/run-chunk-n-mc "HP-chunk-n-mc OK" "$out" has http-parser/run-chunk-body-final "HP-chunk-body-final OK" "$out" has http-parser/run-chunk-scatter-consumed "HP-chunk-scatter-consumed OK" "$out" has http-parser/run-chunk-scatter-seq "HP-chunk-scatter-seq OK" "$out" has http-parser/run-chunk-scatter-body "HP-chunk-scatter-body OK" "$out" has http-parser/run-chunk-scatter-sizes "HP-chunk-scatter-sizes OK" "$out" # content_length is uint64_t -- i64 on wasm32. 2^32 and 2^53+1 are past what a # 32-bit accumulator holds, the scatter case multiplies the accumulator across # re-entries one digit at a time, and upstream's overflow guard (t < # content_length || t == ULLONG_MAX) is exactly the arithmetic a 32-bit-native # arm gets wrong. has http-parser/run-clen-2p32 "HP-clen-2p32 OK" "$out" has http-parser/run-clen-2p32-errno "HP-clen-2p32-errno OK" "$out" has http-parser/run-clen-2p53p1 "HP-clen-2p53p1 OK" "$out" has http-parser/run-clen-2p53p1-scatter "HP-clen-2p53p1-scatter OK" "$out" has http-parser/run-clen-overflow-errno "HP-clen-overflow-errno OK" "$out" has http-parser/run-clen-duplicate-errno "HP-clen-duplicate-errno OK" "$out" # the keep-alive matrix: HTTP/1.1 defaults open and 1.0 defaults closed, each # overridable by a Connection header. has http-parser/run-ka-11-default "HP-ka-11-default OK" "$out" has http-parser/run-ka-11-close "HP-ka-11-close OK" "$out" has http-parser/run-ka-10-default "HP-ka-10-default OK" "$out" has http-parser/run-ka-10-keepalive "HP-ka-10-keepalive OK" "$out" has http-parser/run-ka-10-minor "HP-ka-10-minor OK" "$out" # two messages through ONE parser with no re-init between them -- the state # machine must return to its start state at message complete. has http-parser/run-pipe-consumed "HP-pipe-consumed OK" "$out" has http-parser/run-pipe-n-mb "HP-pipe-n-mb OK" "$out" has http-parser/run-pipe-n-mc "HP-pipe-n-mc OK" "$out" has http-parser/run-pipe-method-last "HP-pipe-method-last OK" "$out" has http-parser/run-pipe-url "HP-pipe-url OK" "$out" has http-parser/run-pipe-body "HP-pipe-body OK" "$out" has http-parser/run-pipe-seq "HP-pipe-seq OK" "$out" # Upgrade and CONNECT: both make http_parser_execute stop early and hand back # the offset of the first unparsed byte, as a RETURN VALUE rather than an # error. Getting that offset wrong silently truncates or duplicates a caller's # payload. has http-parser/run-upgrade-flag "HP-upgrade-flag OK" "$out" has http-parser/run-upgrade-errno "HP-upgrade-errno OK" "$out" has http-parser/run-upgrade-stops-before-payload "HP-upgrade-stops-before-payload OK" "$out" has http-parser/run-upgrade-body-empty "HP-upgrade-body-empty OK" "$out" has http-parser/run-upgrade-hdrs "HP-upgrade-hdrs OK" "$out" has http-parser/run-connect-method "HP-connect-method OK" "$out" has http-parser/run-connect-url "HP-connect-url OK" "$out" has http-parser/run-connect-upgrade "HP-connect-upgrade OK" "$out" has http-parser/run-connect-consumed "HP-connect-consumed OK" "$out" # the on_headers_complete return protocol: 0 continue, 1 no body follows, -1 # abort. These are values flowing BACK out of an indirect call into the state # machine's control flow, which is the opposite direction from every case # above. has http-parser/run-hc-ret0-body "HP-hc-ret0-body OK" "$out" has http-parser/run-hc-ret1-no-body "HP-hc-ret1-no-body OK" "$out" has http-parser/run-hc-ret1-errno "HP-hc-ret1-errno OK" "$out" has http-parser/run-hc-ret1-errno-name "HP-hc-ret1-errno-name OK" "$out" has http-parser/run-hc-ret1-consumed "HP-hc-ret1-consumed OK" "$out" has http-parser/run-hc-abort-errno "HP-hc-abort-errno OK" "$out" has http-parser/run-hc-abort-errno-name "HP-hc-abort-errno-name OK" "$out" # explicit pause and resume across the callback boundary -- http_parser_pause # called from inside a callback must stop the machine where it stands and let a # later execute pick it up mid-message. has http-parser/run-pause-errno "HP-pause-errno OK" "$out" has http-parser/run-pause-errno-name "HP-pause-errno-name OK" "$out" has http-parser/run-pause-body-empty "HP-pause-body-empty OK" "$out" has http-parser/run-resume-errno "HP-resume-errno OK" "$out" has http-parser/run-resume-consumed "HP-resume-consumed OK" "$out" has http-parser/run-resume-body "HP-resume-body OK" "$out" has http-parser/run-resume-n-mc "HP-resume-n-mc OK" "$out" # the error paths, each pinned to its HPE_ code. has http-parser/run-err-method "HP-err-method OK" "$out" has http-parser/run-err-version-digits "HP-err-version-digits OK" "$out" has http-parser/run-err-hdr-token "HP-err-hdr-token OK" "$out" has http-parser/run-err-url "HP-err-url OK" "$out" has http-parser/run-err-chunk "HP-err-chunk OK" "$out" # THE SHIPPED ARCHIVE IS THE NON-STRICT BUILD. Upstream's `package` target # compiles http_parser.o with CPPFLAGS_FAST = -DHTTP_PARSER_STRICT=0, so a bare # LF terminates a line and the version CONSTANT is not checked (the version # DIGITS still are -- err-version-digits above). A space inside the request # target is still rejected, so "non-strict" does not mean "accepts anything". # These assert which object the recipe shipped. has http-parser/run-lenient-bare-lf-errno "HP-lenient-bare-lf-errno OK" "$out" has http-parser/run-lenient-bare-lf-url "HP-lenient-bare-lf-url OK" "$out" has http-parser/run-lenient-bare-lf-hdrs "HP-lenient-bare-lf-hdrs OK" "$out" has http-parser/run-lenient-version-constant-errno "HP-lenient-version-constant-errno OK" "$out" has http-parser/run-lenient-version-constant-major "HP-lenient-version-constant-major OK" "$out" has http-parser/run-lenient-version-constant-minor "HP-lenient-version-constant-minor OK" "$out" has http-parser/run-strict-url-space-errno "HP-strict-url-space-errno OK" "$out" has http-parser/run-strict-url-space-url "HP-strict-url-space-url OK" "$out" # the header-size ceiling, and the fact that nread is REWOUND at message # complete rather than left holding the message length. has http-parser/run-maxhdr-overflow "HP-maxhdr-overflow OK" "$out" has http-parser/run-maxhdr-restored "HP-maxhdr-restored OK" "$out" has http-parser/run-maxhdr-nread-rewound "HP-maxhdr-nread-rewound OK" "$out" # http_parser_parse_url: a SECOND state machine, writing uint16_t off/len pairs # into a struct the caller owns. Every field is read back OUT of the caller's # buffer at the offsets the library wrote, so a wrong offset shows as wrong TEXT # rather than as a silent mask difference. The bad-URL rows include one that # pins partial writes on the error path. has http-parser/run-url-full-rc "HP-url-full-rc OK" "$out" has http-parser/run-url-full-port "HP-url-full-port OK" "$out" has http-parser/run-url-full-fieldset "HP-url-full-fieldset OK" "$out" has http-parser/run-url-full-schema "HP-url-full-schema OK" "$out" has http-parser/run-url-full-host "HP-url-full-host OK" "$out" has http-parser/run-url-full-port-text "HP-url-full-port-text OK" "$out" has http-parser/run-url-full-path "HP-url-full-path OK" "$out" has http-parser/run-url-full-query "HP-url-full-query OK" "$out" has http-parser/run-url-full-fragment "HP-url-full-fragment OK" "$out" has http-parser/run-url-full-userinfo "HP-url-full-userinfo OK" "$out" has http-parser/run-url-full-host-off "HP-url-full-host-off OK" "$out" has http-parser/run-url-full-host-len "HP-url-full-host-len OK" "$out" has http-parser/run-url-rel-rc "HP-url-rel-rc OK" "$out" has http-parser/run-url-rel-path "HP-url-rel-path OK" "$out" has http-parser/run-url-rel-query "HP-url-rel-query OK" "$out" has http-parser/run-url-rel-host "HP-url-rel-host OK" "$out" has http-parser/run-url-rel-schema "HP-url-rel-schema OK" "$out" has http-parser/run-url-rel-port "HP-url-rel-port OK" "$out" has http-parser/run-url-connect-rc "HP-url-connect-rc OK" "$out" has http-parser/run-url-connect-host "HP-url-connect-host OK" "$out" has http-parser/run-url-connect-port "HP-url-connect-port OK" "$out" has http-parser/run-url-connect-needs-flag "HP-url-connect-needs-flag OK" "$out" has http-parser/run-url-ipv6-rc "HP-url-ipv6-rc OK" "$out" has http-parser/run-url-ipv6-host "HP-url-ipv6-host OK" "$out" has http-parser/run-url-ipv6-port "HP-url-ipv6-port OK" "$out" has http-parser/run-url-ipv6-path "HP-url-ipv6-path OK" "$out" has http-parser/run-url-opaque-schema-rejected "HP-url-opaque-schema-rejected OK" "$out" has http-parser/run-url-opaque-schema-partial-fieldset "HP-url-opaque-schema-partial-fieldset OK" "$out" has http-parser/run-url-opaque-schema-text "HP-url-opaque-schema-text OK" "$out" has http-parser/run-url-bad-empty "HP-url-bad-empty OK" "$out" has http-parser/run-url-bad-schema "HP-url-bad-schema OK" "$out" has http-parser/run-url-bad-port-huge "HP-url-bad-port-huge OK" "$out" has http-parser/run-url-bad-port-text "HP-url-bad-port-text OK" "$out" has http-parser/run-url-bad-connect-nohost "HP-url-bad-connect-nohost OK" "$out" has http-parser/run-url-init-fieldset "HP-url-init-fieldset OK" "$out" has http-parser/run-url-init-port "HP-url-init-port OK" "$out" has http-parser/run-url-init-off0 "HP-url-init-off0 OK" "$out" # the string tables -- static const char *const arrays reached by enum index. # Read-only data through a table is a different access path from anything the # parser code exercises, and an out-of-range index must yield "" # rather than read off the end. has http-parser/run-str-method-delete "HP-str-method-delete OK" "$out" has http-parser/run-str-method-get "HP-str-method-get OK" "$out" has http-parser/run-str-method-head "HP-str-method-head OK" "$out" has http-parser/run-str-method-post "HP-str-method-post OK" "$out" has http-parser/run-str-method-put "HP-str-method-put OK" "$out" has http-parser/run-str-method-connect "HP-str-method-connect OK" "$out" has http-parser/run-str-method-options "HP-str-method-options OK" "$out" has http-parser/run-str-method-trace "HP-str-method-trace OK" "$out" has http-parser/run-str-method-patch "HP-str-method-patch OK" "$out" has http-parser/run-str-method-mkcalendar "HP-str-method-mkcalendar OK" "$out" has http-parser/run-str-method-source "HP-str-method-source OK" "$out" has http-parser/run-str-method-oob "HP-str-method-oob OK" "$out" has http-parser/run-str-status-200 "HP-str-status-200 OK" "$out" has http-parser/run-str-status-101 "HP-str-status-101 OK" "$out" has http-parser/run-str-status-404 "HP-str-status-404 OK" "$out" has http-parser/run-str-status-417 "HP-str-status-417 OK" "$out" has http-parser/run-str-status-500 "HP-str-status-500 OK" "$out" has http-parser/run-str-status-oob "HP-str-status-oob OK" "$out" has http-parser/run-str-errno-ok "HP-str-errno-ok OK" "$out" has http-parser/run-str-errno-paused "HP-str-errno-paused OK" "$out" has http-parser/run-str-errno-method "HP-str-errno-method OK" "$out" has http-parser/run-str-errno-overflow "HP-str-errno-overflow OK" "$out" has http-parser/run-str-desc-ok "HP-str-desc-ok OK" "$out" has http-parser/run-str-desc-paused "HP-str-desc-paused OK" "$out" has http-parser/run-str-desc-method "HP-str-desc-method OK" "$out" # an all-NULL settings struct must parse the same message to the same end state: # the library null-checks every one of the ten indirect calls. has http-parser/run-nullcb-consumed "HP-nullcb-consumed OK" "$out" has http-parser/run-nullcb-errno "HP-nullcb-errno OK" "$out" has http-parser/run-nullcb-method "HP-nullcb-method OK" "$out" # a body terminated by EOF rather than by length or chunking, where the # zero-length execute call IS the end-of-stream signal. has http-parser/run-eof-consumed "HP-eof-consumed OK" "$out" has http-parser/run-eof-mc-before "HP-eof-mc-before OK" "$out" has http-parser/run-eof-body "HP-eof-body OK" "$out" has http-parser/run-eof-mc-after "HP-eof-mc-after OK" "$out" has http-parser/run-eof-errno "HP-eof-errno OK" "$out" # The arm-dependent line, which is the ONE the control and this arm must # legitimately differ on -- pointer width, and the two struct sizes that follow # from it. It is asserted here by shape and then EXCLUDED from the byte-diff # below rather than allowed to fail it. sizeof(http_parser) is deliberately NOT # on this line: it agrees at 32 on both arms and is asserted as run-sizeof-parser # above. has http-parser/run-probe-banner "HP-PROBE http-parser probe, 32-bit pointers" "$out" # BYTE-IDENTITY AGAINST THE NATIVE CONTROL, asserted here ON TARGET rather than # by eyeballing two logs off-target. data/http-parser-native.txt is the verbatim # output of this same probe source built natively against a host build of the # identical release, with the HP-PROBE banner removed. Comparing it inside the # guest keeps every off-target transport out of the comparison -- the console # dump truncates long lines (BRINTOS-260) and the expect-backed host SSH is # pty-based and rewrites LF to CRLF (BRINTOS-263), and this output carries whole # header transcripts on single lines -- and it turns "matches native" from a # one-off manual check into a permanent regression guard: a platform change in # 64-bit arithmetic, in the indirect-call path, or in the coroutine rewrite's # handling of a resumed state machine shows up as a CHANGED VALUE here even if # every verdict above still passes. ctl=$BST_DATA/http-parser-native.txt gotf=${TMPDIR:-/tmp}/bst-http-parser-got.$$ printf '%s\n' "$out" | grep -v '^HP-PROBE ' > "$gotf" 2>/dev/null if [ ! -s "$ctl" ]; then bst_notok http-parser/native-byte-identical "control absent or empty: $ctl" elif cmp -s "$ctl" "$gotf"; then bst_ok http-parser/native-byte-identical else bst_notok http-parser/native-byte-identical \ "first diff: $(diff "$ctl" "$gotf" 2>/dev/null | sed -n '2,3p' | tr '\n' ' ' | cut -c1-90)" fi rm -f "$gotf" # The probe's own tally and its exit status. 206/206 is what the same source # scores natively against a host build of the identical release. has http-parser/run-summary "HP-SUMMARY 206/206" "$out" check_eq http-parser/run-exit0 0 "$prc" rm -f "$probe" else bst_notok http-parser/run-stage "cannot stage $BST_DATA/http-parser-probe" fi