• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacks-network / stacks-core / 25903914664-1

15 May 2026 06:28AM UTC coverage: 47.122% (-38.8%) from 85.959%
25903914664-1

Pull #7199

github

94e391
web-flow
Merge 109f2828c into 1c7b8e6ac
Pull Request #7199: Feat: L1 and L2 early unlocks, updating signer

103343 of 219309 relevant lines covered (47.12%)

12880462.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

47.14
/stackslib/src/net/http/common.rs
1
// Copyright (C) 2013-2020 Blockstack PBC, a public benefit corporation
2
// Copyright (C) 2020-2023 Stacks Open Internet Foundation
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16

17
use std::io::Read;
18

19
use stacks_common::codec::{read_next, StacksMessageCodec};
20
use stacks_common::types::net::PeerHost;
21

22
use crate::net::http::{Error, HttpContentType, HttpResponsePreamble};
23

24
/// HTTP version (1.0 or 1.1)
25
#[derive(Debug, Clone, PartialEq, Copy, Hash)]
26
#[repr(u8)]
27
pub enum HttpVersion {
28
    Http10 = 0x10,
29
    Http11 = 0x11,
30
}
31

32
/// HTTP headers that we really care about
33
#[derive(Debug, Clone, PartialEq)]
34
pub enum HttpReservedHeader {
35
    ContentLength(u32),
36
    ContentType(HttpContentType),
37
    Host(PeerHost),
38
}
39

40
impl HttpReservedHeader {
41
    pub fn is_reserved(header: &str) -> bool {
10,292,781✔
42
        matches!(header, "content-length" | "content-type" | "host")
10,292,781✔
43
    }
10,292,781✔
44

45
    pub fn try_from_str(header: &str, value: &str) -> Option<HttpReservedHeader> {
×
46
        let hdr = header.to_string().to_lowercase();
×
47
        match hdr.as_str() {
×
48
            "content-length" => match value.parse::<u32>() {
×
49
                Ok(cl) => Some(HttpReservedHeader::ContentLength(cl)),
×
50
                Err(_) => None,
×
51
            },
52
            "content-type" => match value.parse::<HttpContentType>() {
×
53
                Ok(ct) => Some(HttpReservedHeader::ContentType(ct)),
×
54
                Err(_) => None,
×
55
            },
56
            "host" => match value.parse::<PeerHost>() {
×
57
                Ok(ph) => Some(HttpReservedHeader::Host(ph)),
×
58
                Err(_) => None,
×
59
            },
60
            _ => None,
×
61
        }
62
    }
×
63
}
64

65
/// Maximum size of all of the HTTP headers in a request or response
66
pub const HTTP_PREAMBLE_MAX_ENCODED_SIZE: u32 = 4096;
67
/// Maximum number of headers in an HTTP request or response
68
pub const HTTP_PREAMBLE_MAX_NUM_HEADERS: usize = 64;
69

70
/// Helper function to parse a SIP-003 bytestream.  The first 4 bytes are a big-endian length prefix
71
pub fn parse_bytestream<R: Read, T: StacksMessageCodec>(
×
72
    preamble: &HttpResponsePreamble,
×
73
    mut body: &[u8],
×
74
) -> Result<T, Error> {
×
75
    // content-type has to be Bytes
76
    if preamble.content_type != HttpContentType::Bytes {
×
77
        return Err(Error::DecodeError(
×
78
            "Invalid content-type: expected application/octet-stream".to_string(),
×
79
        ));
×
80
    }
×
81

82
    let item: T = read_next(&mut body)?;
×
83
    Ok(item)
×
84
}
×
85

86
/// Helper function to decode an HTTP response preamble and its request body (as an `fd`) into a
87
/// JSON object
88
pub fn parse_json<T: serde::de::DeserializeOwned>(
561,299✔
89
    preamble: &HttpResponsePreamble,
561,299✔
90
    body: &[u8],
561,299✔
91
) -> Result<T, Error> {
561,299✔
92
    // content-type has to be JSON
93
    if preamble.content_type != HttpContentType::JSON {
561,299✔
94
        return Err(Error::DecodeError(
×
95
            "Invalid content-type: expected application/json".to_string(),
×
96
        ));
×
97
    }
561,299✔
98

99
    let item_result: Result<T, serde_json::Error> = serde_json::from_slice(body);
561,299✔
100
    item_result.map_err(|e| {
561,299✔
101
        if e.is_eof() {
×
102
            Error::UnderflowError("Not enough bytes to parse JSON".to_string())
×
103
        } else {
104
            Error::DecodeError(format!("Failed to parse JSON: {:?}", &e))
×
105
        }
106
    })
×
107
}
561,299✔
108

109
/// Helper function to read a raw bytestream
110
pub fn parse_raw_bytes(
4,719,305✔
111
    preamble: &HttpResponsePreamble,
4,719,305✔
112
    body: &[u8],
4,719,305✔
113
    max_len: u64,
4,719,305✔
114
    expected_content_type: HttpContentType,
4,719,305✔
115
) -> Result<Vec<u8>, Error> {
4,719,305✔
116
    if preamble.content_type != expected_content_type {
4,719,305✔
117
        return Err(Error::DecodeError(format!(
×
118
            "Invalid content-type: expected {}",
×
119
            expected_content_type
×
120
        )));
×
121
    }
4,719,305✔
122
    let out_len = usize::try_from(max_len).unwrap().min(body.len());
4,719,305✔
123
    let out_bytes = body
4,719,305✔
124
        .get(..out_len)
4,719,305✔
125
        .ok_or_else(|| Error::DecodeError("Unexpected body size".into()))?;
4,719,305✔
126
    Ok(out_bytes.to_vec())
4,719,305✔
127
}
4,719,305✔
128

129
/// Helper function to read `application/octet-stream` content
130
pub fn parse_bytes(
4,719,305✔
131
    preamble: &HttpResponsePreamble,
4,719,305✔
132
    body: &[u8],
4,719,305✔
133
    max_len: u64,
4,719,305✔
134
) -> Result<Vec<u8>, Error> {
4,719,305✔
135
    parse_raw_bytes(preamble, body, max_len, HttpContentType::Bytes)
4,719,305✔
136
}
4,719,305✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc