nucleus_http/
request.rs

1use crate::{
2    http::{Header, Method, Version},
3    utils,
4};
5use bytes::Bytes;
6use core::fmt;
7use memchr::{memchr, memchr_iter, memmem};
8use std::{collections::HashMap, format, vec};
9
10#[derive(Debug, Clone, PartialEq, Eq)]
11pub enum FormTypes {
12    None,
13    MultiPart(HashMap<String, MultiPartFormEntry>),
14    XUrlEncoded(HashMap<String, String>), //simple string key value pair
15}
16
17#[derive(PartialEq, Debug, Clone)]
18pub struct Request {
19    method: Method,
20    path: String,
21    version: Version,
22    host: String,
23    query_string: Option<String>,
24    headers: HashMap<String, String>,
25    body: Vec<u8>,
26    form_data: FormTypes,
27    keep_alive: bool,
28}
29
30#[derive(PartialEq, Debug, Clone, Copy)]
31pub enum Error {
32    InvalidString,
33    InvalidMethod,
34    InvalidHTTPVersion,
35    MissingBlankLine,
36    NoHostHeader,
37    InvalidContentLength,
38    WaitingOnBody(Option<usize>), // this can return number of bytes left in body
39    MissingMultiPartBoundary,
40    MissingContentLength,
41    InvalidUrlEncodedForm,
42}
43
44impl std::error::Error for Error {
45    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
46        None
47    }
48}
49
50impl From<&Error> for String {
51    fn from(value: &Error) -> Self {
52        match value {
53            Error::InvalidString => "Invalid String".to_string(),
54            Error::NoHostHeader => "No VHost Specified".to_string(),
55            Error::InvalidMethod => "Invalid Method Requested".to_string(),
56            Error::InvalidHTTPVersion => "Unsupported HTTP version Request".to_string(),
57            Error::MissingBlankLine => "Missing Blank Line".to_string(),
58            Error::WaitingOnBody(_) => "Waiting On Body".to_string(),
59            Error::InvalidContentLength => "Content Length Invalid".to_string(),
60            Error::MissingMultiPartBoundary => "Missing Mulipart boundary".to_string(),
61            Error::MissingContentLength => "Missing Content Length Header".to_string(),
62            Error::InvalidUrlEncodedForm => "Invalid URL Encoded Form".to_string(),
63        }
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct MultiPartFormEntry {
69    name: String,
70    file_name: Option<String>,
71    content_type: Option<String>,
72    value: Vec<u8>,
73}
74
75impl MultiPartFormEntry {
76    pub fn from_string(form_str: &str) -> Result<MultiPartFormEntry, anyhow::Error> {
77        //first split out body
78        let split: Vec<_> = form_str.split("\r\n\r\n").collect();
79        if let (Some(header), Some(body)) = (split.first(), split.get(1)) {
80            let lines = header.split("\r\n");
81            let mut form_args: HashMap<&str, &str> = HashMap::new();
82            let mut content_type = None;
83            for line in lines {
84                let name_value_split: Vec<_> = line.split(": ").collect();
85                if let (Some(header_name), Some(header_value)) =
86                    (name_value_split.first(), name_value_split.get(1))
87                {
88                    match header_name.to_lowercase().as_str() {
89                        "content-type" => {
90                            content_type = Some(header_value.to_string());
91                        }
92                        "content-disposition" => {
93                            let split = header_value.split("; ");
94                            for op in split {
95                                let nv: Vec<_> = op.split('=').collect();
96                                if let (Some(n), Some(v)) = (nv.first(), nv.get(1)) {
97                                    form_args.insert(n, strip_quotes(v));
98                                }
99                            }
100                        }
101                        _ => {}
102                    }
103                }
104            }
105            if let Some(name) = form_args.get("name") {
106                let name = name.to_string();
107                let file = form_args.get("filename").map(|s| s.to_string());
108                Ok(MultiPartFormEntry {
109                    name,
110                    file_name: file,
111                    content_type,
112                    value: body.as_bytes().into(),
113                })
114            } else {
115                Err(anyhow::Error::msg("Missing Name"))
116            }
117        } else {
118            Err(anyhow::Error::msg("Missing Body"))
119        }
120    }
121
122    pub fn from_bytes(form: &[u8]) -> Result<MultiPartFormEntry, anyhow::Error> {
123        //first split out body
124        if let Some(blank_line) = memmem::find(form, b"\r\n\r\n") {
125            let mut form_args: HashMap<String, String> = HashMap::new();
126            let mut content_type = None;
127            let header = &form[0..blank_line + 2];
128            let mut body = &form[blank_line + 4..];
129            if body[body.len() - 1] == b'\n' && body[body.len() - 2] == b'\r' {
130                body = &body[0..body.len() - 2]; // trim crlf at end of body if there
131            }
132            let newline_iter = memmem::find_iter(header, "\r\n");
133            let mut last_header_start = 0;
134            for i in newline_iter {
135                let new_header = &header[last_header_start..i];
136                last_header_start = i + 2;
137                if let Some(colon_i) = memmem::find(new_header, b": ") {
138                    let name_b = &new_header[0..colon_i];
139                    let name = String::from_utf8_lossy(name_b);
140                    let value = &new_header[colon_i + 2..];
141                    match name.to_lowercase().as_str() {
142                        "content-type" => {
143                            content_type = Some(String::from_utf8_lossy(value).to_string());
144                        }
145                        "content-disposition" => {
146                            let header_value = String::from_utf8_lossy(value).to_string();
147                            let split = header_value.split("; ");
148                            for op in split {
149                                let nv: Vec<_> = op.split('=').collect();
150                                if let (Some(n), Some(v)) = (nv.first(), nv.get(1)) {
151                                    form_args.insert(n.to_string(), strip_quotes(v).to_string());
152                                }
153                            }
154                        }
155                        _ => {}
156                    }
157                }
158            }
159            if let Some(name) = form_args.get("name") {
160                let name = name.to_string();
161                let file = form_args.get("filename").map(|s| s.to_string());
162                Ok(MultiPartFormEntry {
163                    name,
164                    file_name: file,
165                    content_type,
166                    value: body.into(),
167                })
168            } else {
169                Err(anyhow::Error::msg("Missing Name"))
170            }
171        } else {
172            Err(anyhow::Error::msg("Missing Body"))
173        }
174    }
175
176    pub fn name_value(name: &str, value: &str) -> Self {
177        MultiPartFormEntry {
178            name: name.to_string(),
179            file_name: None,
180            content_type: None,
181            value: value.to_string().into(),
182        }
183    }
184
185    pub fn file(name: &str, file_name: &str, value: &str) -> Self {
186        MultiPartFormEntry {
187            name: name.to_string(),
188            file_name: Some(file_name.to_string()),
189            content_type: None,
190            value: value.to_string().into(),
191        }
192    }
193
194    pub fn file_name(&self) -> Option<&String> {
195        self.file_name.as_ref()
196    }
197
198    pub fn content_type(&self) -> Option<&String> {
199        self.content_type.as_ref()
200    }
201
202    pub fn value(&self) -> &[u8] {
203        self.value.as_ref()
204    }
205
206    pub fn name(&self) -> &str {
207        self.name.as_ref()
208    }
209}
210impl fmt::Display for Error {
211    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212        write!(f, "{}", String::from(self))
213    }
214}
215
216impl From<Error> for String {
217    fn from(value: Error) -> Self {
218        String::from(&value)
219    }
220}
221
222fn get_boundary(content_type_value_str: &str) -> Result<&str, anyhow::Error> {
223    let parts: Vec<_> = content_type_value_str.split(';').collect();
224    if parts.len() > 1 {
225        let nv: Vec<_> = parts[1].split('=').collect();
226        if let Some(boundary) = nv.get(1) {
227            Ok(strip_quotes(boundary))
228        } else {
229            Err(anyhow::Error::msg("Invalid boundary"))
230        }
231    } else {
232        Err(anyhow::Error::msg("Boundary Missing from string"))
233    }
234}
235
236fn get_multiparts_entries_from_bytes(
237    body: &[u8],
238    boundary: &[u8],
239) -> anyhow::Result<HashMap<String, MultiPartFormEntry>> {
240    let mut end_marker = vec![b'-', b'-'];
241    end_marker.extend_from_slice(boundary);
242    let boundary_marker = end_marker.clone();
243    end_marker.extend_from_slice(b"--");
244    if memmem::find(body, &end_marker).is_some() {
245        //we have an en marker go through the bodies, body is anything after marker before next
246        //marker or end boundary
247        let mut body_spliter = memmem::find_iter(body, &boundary_marker);
248        let mut entries = HashMap::new();
249        if let Some(mut last_bound) = body_spliter.next() {
250            last_bound += boundary_marker.len();
251            for bound in body_spliter {
252                let current_body = &body[last_bound..bound];
253                last_bound = bound + boundary_marker.len();
254                //FIXME: make this use bytes
255                if let Ok(entry) = MultiPartFormEntry::from_bytes(current_body) {
256                    entries.insert(entry.name.clone(), entry);
257                }
258            }
259        } else {
260            return Err(anyhow::Error::msg("Missing boundaries"));
261        }
262        Ok(entries)
263    } else {
264        Err(anyhow::Error::msg("Not Full Body"))
265    }
266}
267
268fn strip_quotes(value: &str) -> &str {
269    let split: Vec<_> = value.split('\"').collect();
270    if let Some(v) = split.get(1) {
271        v
272    } else {
273        split[0]
274    }
275}
276
277impl Request {
278    pub fn ok(&self) -> String {
279        match self.version {
280            Version::V0_9 => "200 OK\r\n".to_owned(),
281            Version::V1_0 => "HTTP/1.0 200 OK\r\n".to_owned(),
282            Version::V1_1 => "HTTP/1.1 200 OK\r\n".to_owned(),
283            Version::V2_0 => "HTTP/2 200 OK\r\n".to_owned(),
284        }
285    }
286
287    pub fn error(&self, code: u32, message: &str) -> String {
288        format!("{} {} {}\r\n", self.version, code, message)
289    }
290
291    pub fn method(&self) -> &Method {
292        &self.method
293    }
294
295    pub fn path(&self) -> &str {
296        &self.path
297    }
298
299    pub fn version(&self) -> Version {
300        self.version
301    }
302
303    pub fn hostname(&self) -> &str {
304        &self.host
305    }
306
307    pub fn body(&self) -> &Vec<u8> {
308        &self.body
309    }
310
311    pub fn get_header_value(&self, header_name: &str) -> Option<String> {
312        let lower = header_name.to_lowercase();
313        Self::header_value(&self.headers, &lower)
314    }
315
316    pub fn header_value(headers: &HashMap<String, String>, header_name: &str) -> Option<String> {
317        let lower = header_name.to_lowercase();
318        return headers.get(&lower).cloned();
319    }
320
321    pub fn keep_alive(&self) -> bool {
322        self.keep_alive
323    }
324
325    pub fn from_lines(lines: &Vec<&str>) -> Result<Request, Error> {
326        let mut headers = HashMap::new();
327        let host;
328        let mut query_string = None;
329        let body = vec![];
330        let form_data = FormTypes::None;
331
332        let request_seperated: Vec<&str> = lines[0].split(' ').collect(); //First line is request
333        if request_seperated.len() < 3 {
334            return Err(Error::InvalidString);
335        }
336
337        //First is method
338        let method = match request_seperated[0] {
339            "GET" => Method::GET,
340            "POST" => Method::POST,
341            _ => return Err(Error::InvalidMethod),
342        };
343
344        //second string is url
345        let url = request_seperated[1].to_string();
346        let url_split: Vec<&str> = url.split('?').collect(); //anything after ? is query string
347        let path = url_split[0].to_string();
348        if url_split.len() > 1 {
349            query_string = Some(url_split[1].to_string());
350        }
351
352        //third is http Verison
353        let version = match request_seperated[2] {
354            "HTTP/1.0" => Version::V1_0,
355            "HTTP/1.1" => Version::V1_1,
356            "HTTP/2.2" => Version::V2_0,
357            _ => return Err(Error::InvalidHTTPVersion),
358        };
359
360        //4th is optional headers
361        if lines.len() > 1 {
362            //FIXME: Dont we need to collect here?
363            for line in lines.iter().skip(1) {
364                if let Ok(header) = Header::try_from(*line) {
365                    headers.insert(header.key, header.value);
366                }
367                //headers.push(lines[i].to_string());
368            }
369        }
370
371        let op_host = Self::header_value(&headers, "Host");
372        if let Some(hostname) = op_host {
373            // get rid if port if its included in host name
374            let hostname_only: Vec<&str> = hostname.split(':').collect();
375            host = hostname_only[0].to_string();
376        } else {
377            //FIXME: should we only error when its > http 1.0????
378            return Err(Error::NoHostHeader);
379        }
380        //last is optional headers
381        let keep_alive = Self::determine_keep_alive(version, headers.get("connection"));
382        Ok(Request {
383            method,
384            version,
385            path,
386            headers,
387            host,
388            query_string,
389            body,
390            form_data,
391            keep_alive,
392        })
393    }
394
395    pub fn from_bytes(request_bytes: Bytes) -> Result<Request, Error> {
396        let bytes = request_bytes;
397        if bytes.is_empty() {
398            return Err(Error::InvalidString);
399        }
400        //first split the header from the body, first \r\n\r\n should seperate that
401        if let Some(blank_line_index) = memmem::find(&bytes, b"\r\n\r\n") {
402            let req_header = bytes.slice(0..blank_line_index + 2); //include last crlf for easier
403                                                                   //header parsing
404            let mut req_body = bytes.slice(blank_line_index + 4..bytes.len());
405            let mut req_header_lines = memmem::find_iter(&req_header, "\r\n");
406            if let Some(i) = req_header_lines.next() {
407                let url;
408                let mut headers = HashMap::new(); 
409                let host;
410                let mut query_string = None;
411                let mut form_data = FormTypes::None;
412                let request_line = req_header.slice(0..i);
413                let mut header_start = i + 2;
414                let mut space_iter = memchr_iter(b' ', &request_line);
415                let method_end = space_iter.next().ok_or(Error::InvalidString)?;
416                let url_end = space_iter.next().ok_or(Error::InvalidString)?;
417                let method_b = request_line.slice(0..method_end);
418                let url_b = request_line.slice(method_end + 1..url_end);
419                let version_b = request_line.slice(url_end + 1..request_line.len());
420
421                let method: Method =
422                    Method::try_from(method_b.as_ref()).map_err(|_| Error::InvalidMethod)?;
423                let version =
424                    Version::try_from(version_b.as_ref()).map_err(|_| Error::InvalidHTTPVersion)?;
425                //check for query_string in url
426                if let Some(qmark) = memchr(b'?', &url_b) {
427                    let query = url_b.slice(qmark + 1..url_b.len());
428                    let url_slice = url_b.slice(0..qmark);
429                    query_string = Some(String::from_utf8_lossy(query.as_ref()).to_string());
430                    url = String::from_utf8_lossy(url_slice.as_ref()).to_string();
431                } else {
432                    url = String::from_utf8_lossy(url_b.as_ref()).to_string();
433                }
434
435                // go through rest of the lines in header and parse out any headers
436                for line_end in req_header_lines {
437                    let header_line = req_header.slice(header_start..line_end);
438                    header_start = line_end + 2;
439                    if let Ok(header) = Header::try_from(header_line.as_ref()) {
440                        headers.insert(header.key, header.value);
441                    }
442                }
443
444                //make sure we have a host header
445                let op_host = Self::header_value(&headers, "Host");
446                if let Some(hostname) = op_host {
447                    // get rid if port if its included in host name
448                    let hostname_only: Vec<&str> = hostname.split(':').collect();
449                    host = hostname_only[0].to_string();
450                } else {
451                    //FIXME: should we only error when its > http 1.0????
452                    return Err(Error::NoHostHeader);
453                }
454
455                //lastly check we got the full body of the request
456                if let Some(content_length) = Self::header_value(&headers, "Content-Length") {
457                    if let Ok(len) = content_length.parse() {
458                        if req_body.len() < len {
459                            return Err(Error::WaitingOnBody(Some(len - req_body.len())));
460                        }
461                    } else {
462                        return Err(Error::InvalidContentLength);
463                    }
464                }
465                if let Some(content_type) = Self::header_value(&headers, "Content-Type") {
466                    match content_type {
467                        x if x.contains("multipart/form-data;") => {
468                            match get_boundary(&x) {
469                                Ok(boundary) => {
470                                    match get_multiparts_entries_from_bytes(
471                                        &req_body,
472                                        boundary.as_bytes(),
473                                    ) {
474                                        Ok(entries) => {
475                                            form_data = FormTypes::MultiPart(entries);
476                                            req_body.clear(); //clear since we parsed it
477                                                              //return Ok(req);
478                                        }
479                                        Err(_) => {
480                                            return Err(Error::WaitingOnBody(None));
481                                        }
482                                    }
483                                }
484                                Err(e) => {
485                                    log::debug!("Error Parsing Boundary: {}", e.to_string());
486                                    return Err(Error::MissingMultiPartBoundary);
487                                }
488                            }
489                        }
490                        x if x.contains("application/x-www-form-urlencoded") => {
491                            //Parse here
492                            match utils::parse_query_string(&req_body) {
493                                Ok(form) => {
494                                    form_data = FormTypes::XUrlEncoded(form);
495                                    req_body.clear();
496                                }
497                                Err(e) => {
498                                    log::error!(
499                                        "Error Parsing URL Encoded Body: {}",
500                                        e.to_string()
501                                    );
502                                    return Err(Error::InvalidUrlEncodedForm);
503                                }
504                            }
505                        }
506                        _ => {}
507                    }
508                }
509                let keep_alive = Self::determine_keep_alive(version, headers.get("connection"));
510                Ok(Request {
511                    method,
512                    version,
513                    path: url,
514                    headers,
515                    host,
516                    query_string,
517                    body: req_body.to_vec(),
518                    form_data,
519                    keep_alive,
520                })
521            } else {
522                //no headers, we need at least the host header
523                panic!("request parsing: Somehow missing CRLF even though CRLFCRLF was present");
524            }
525        } else {
526            Err(Error::MissingBlankLine)
527        }
528    }
529
530    pub fn from_string(request_str: String) -> Result<Request, Error> {
531        let bytes = Bytes::from(request_str);
532        Self::from_bytes(bytes)
533    }
534
535    pub fn query_string(&self) -> Option<&String> {
536        self.query_string.as_ref()
537    }
538
539    pub fn form_data(&self) -> &FormTypes {
540        &self.form_data
541    }
542    
543    /// determin if request wants to keep connection alive
544    /// if connection header present this value is controlled by that
545    /// otherwise determined by default behavior for version passed
546    fn determine_keep_alive(version: Version, connection_header: Option<&String>) -> bool {
547        if let Some(conn) = connection_header {
548            conn.to_lowercase() == "keep-alive"
549        } else {
550            // no conncection header so use version default 
551            match version {
552                Version::V0_9 => false,
553                Version::V1_0 => false,
554                Version::V1_1 => true,
555                Version::V2_0 => true,
556            }
557        }
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use std::assert_eq;
564
565    use super::*;
566
567    #[test]
568    fn x_url_encoded_form() {
569        let mut map = HashMap::new();
570        map.insert("field1".to_string(), "value1".to_string());
571        map.insert("field2".to_string(), "value2".to_string());
572
573        let expected = Request {
574            method: Method::POST,
575            version: Version::V1_1,
576            path: "/test".to_string(),
577            body: vec![],
578            headers: HashMap::from([
579                ("host".to_string(), "foo.example".to_string()),
580                (
581                    "content-type".to_string(),
582                    "application/x-www-form-urlencoded".to_string(),
583                ),
584                ("content-length".to_string(), "27".to_string()),
585            ]),
586            host: "foo.example".to_string(),
587            query_string: None,
588            form_data: FormTypes::XUrlEncoded(map),
589            keep_alive: true,
590        };
591        let request_str = Bytes::from_static(
592            b"POST /test HTTP/1.1\r\n\
593            Host: foo.example\r\n\
594            Content-Type: application/x-www-form-urlencoded\r\n\
595            Content-Length: 27\r\n\r\n\
596            field1=value1&field2=value2",
597        ); //does this normally have CRLF here ?
598        let request = Request::from_bytes(request_str).expect("Could not build request");
599        assert_eq!(expected, request);
600    }
601
602    #[test]
603    fn multipart_form() {
604        let field1 = MultiPartFormEntry::name_value("field1", "value1");
605        let field2 = MultiPartFormEntry::file("field2", "example.txt", "value2");
606        let mut map = HashMap::new();
607        map.insert(field1.name.clone(), field1);
608        map.insert(field2.name.clone(), field2);
609        let expected = Request {
610            method: Method::POST,
611            version: Version::V1_1,
612            path: "/test".to_string(),
613            body: vec![],
614            headers: HashMap::from([
615                ("host".to_string(), "foo.example".to_string()),
616                (
617                    "content-type".to_string(),
618                    "multipart/form-data;boundary=\"boundary\"".to_string(),
619                ),
620            ]),
621            host: "foo.example".to_string(),
622            query_string: None,
623            form_data: FormTypes::MultiPart(map),
624            keep_alive: true,
625        };
626        let request_str = Bytes::from_static(
627            b"POST /test HTTP/1.1\r\n\
628        Host: foo.example\r\n\
629        Content-Type: multipart/form-data;boundary=\"boundary\"\r\n\
630        \r\n\
631        --boundary\r\n\
632        Content-Disposition: form-data; name=\"field1\"\r\n\
633        \r\n\
634        value1\r\n\
635        --boundary\r\n\
636        Content-Disposition: form-data; name=\"field2\"; filename=\"example.txt\"\r\n\
637        \r\n\
638        value2\r\n\
639        --boundary--",
640        );
641
642        let request = Request::from_bytes(request_str).expect("Could not build request");
643        assert_eq!(expected, request);
644    }
645
646    #[test]
647    fn get_wrong_version_new() {
648        let expected = Err(Error::InvalidHTTPVersion);
649        let request =
650            Request::from_bytes(Bytes::from_static(b"GET / HTTP1.1\r\nHost: test\r\n\r\n"));
651        assert_eq!(expected, request);
652    }
653
654    #[test]
655    fn no_blank_line_new() {
656        let expected = Err(Error::MissingBlankLine);
657        let req_str = Bytes::from_static(b"GET / HTTP/1.1");
658        let request = Request::from_bytes(req_str);
659        assert_eq!(expected, request);
660    }
661
662    #[test]
663    fn new() {
664        let expected = Request {
665            method: Method::GET,
666            version: Version::V1_1,
667            path: "/".to_string(),
668            body: vec![],
669            headers: HashMap::from([("host".to_string(), "test".to_string())]),
670            host: "test".to_string(),
671            query_string: None,
672            form_data: FormTypes::None,
673            keep_alive: true,
674        };
675        let request =
676            Request::from_bytes(Bytes::from_static(b"GET / HTTP/1.1\r\nHost: test\r\n\r\n"))
677                .expect("Error Parsing");
678        assert_eq!(expected, request);
679    }
680
681    #[test]
682    fn new_query_string() {
683        let expected = Request {
684            method: Method::GET,
685            version: Version::V1_1,
686            path: "/index.html".to_string(),
687            body: vec![],
688            headers: HashMap::from([("host".to_string(), "test".to_string())]),
689            host: "test".to_string(),
690            query_string: Some("test=true".to_string()),
691            form_data: FormTypes::None,
692            keep_alive: true,
693        };
694        let request = Request::from_bytes(Bytes::from_static(
695            b"GET /index.html?test=true HTTP/1.1\r\nHost: test\r\n\r\n",
696        ))
697        .expect("Error Parsing");
698        assert_eq!(expected, request);
699    }
700
701    #[test]
702    fn new_headers() {
703        let expected = Request {
704            method: Method::GET,
705            version: Version::V1_1,
706            path: "/".to_string(),
707            body: vec![],
708            headers: HashMap::from([
709                ("host".to_string(), "test".to_string()),
710                ("header1".to_string(), "hi".to_string()),
711                ("header2".to_string(), "Bye".to_string()),
712            ]),
713            host: "test".to_string(),
714            query_string: None,
715            form_data: FormTypes::None,
716            keep_alive: true,
717        };
718        let request = Request::from_string(
719            "GET / HTTP/1.1\r\nhost: test\r\nheader1: hi\r\nheader2: Bye\r\n\r\n".to_owned(),
720        )
721        .expect("Error Parsing");
722        assert_eq!(expected, request);
723    }
724
725    #[test]
726    fn empty_string() {
727        let request = Request::from_string("".to_owned());
728        if let Err(error) = request {
729            assert!(error == Error::InvalidString);
730        } else {
731            panic!("No error");
732        }
733    }
734}