1#[cfg(feature = "rspc")]
2use rspc::Type;
3
4use std::path::PathBuf;
5
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9use crate::model::PartialRequest;
10
11#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
12#[cfg_attr(feature = "rspc", derive(Type))]
13#[derive(Error, Debug, PartialEq, Eq, Clone)]
14pub enum ParseError {
15
16 #[error("Could not read the file: '{0}'.")]
17 CouldNotReadRequestFile(PathBuf),
18
19 #[error("Invalid comment start characters: '{0}', comments before the request url should start with '//', '#' or '###'.")]
20 InvalidCommentStart(String),
21
22 #[error("Invalid request URL found: '{0}'. The URL should either be in the form of an URL using host with optional schemes 'http://', 'https://' or it should be a relative url starting with a slash and the 'Host:' header defined.")]
23 InvalidRequestUrl(String),
24
25 #[error("The HTTP version: '{0}' is not valid. A valid HTTP version requires format: 'HTTP/\\d+.\\d+' or 'HTTP/\\d+'.\nFor example 'HTTP/2.1'. You can also omit the version and only specify the url target of the request or the HTTP method and the url target.")]
26 InvalidHttpVersion(String),
27
28 #[error("Expected either a prerequest script within '{{% %}}' blocks or a filepath to a pre-request script after matching '<' character.")]
29 MissingPreRequestScript,
30 #[error("A pre-request script should be ended with '%}}' characters but none were found.")]
31 MissingPreRequestScriptClose,
32
33 #[error("Missing request target line.")]
34 MissingRequestTargetLine,
35 #[error("The request target line containing the url for the request contains too many elements. There should only be a method, the URL and HTTP version. You have additional elements: {0}")]
36 TooManyElementsOnRequestLine(String),
37
38 #[error("Expected header in the form of '<Key>: <Value>'. Found line: {0}")]
39 InvalidHeaderField(String),
40
41 #[error("Missing multipart boundary in 'Content-Type' for 'multipart/form-data'. Using default boundary '{0}' instead.")]
42 MissingMultipartHeaderBoundaryDefinition(String),
43 #[error("Within multipart body expected either a new boundary starting with '{next_boundary}' or finishing a multipart with '{end_boundary}' but none were found.")]
44 MissingMultipartBoundary {
45 next_boundary: String,
46 end_boundary: String,
47 },
48 #[error("Multipart requires a first starting boundary before any content.")]
49 MissingMultipartStartingBoundary,
50 #[error("Could not parse the headers of the given part of a multipart body. Error during parsing: {error_msg}.")]
51 InvalidSingleMultipartHeaders {
52 header_parse_err: Box<ParseError>,
53 error_msg: String,
54 },
55
56 #[error("Missing 'Content-Disposition' header of the multipart part.")]
59 MissingSingleMultipartContentDispositionHeader,
60 #[error("First header of a multipart part should be the 'Content-Disposition' header, found '{0}' instead.")]
62 WrongMultipartContentDispositionHeader(String),
63 #[error("Multipart Content-Disposition should have type 'form-data', found: {0}.")]
65 InvalidMultipartContentDispositionFormData(String),
66 #[error("Expected content disposition values in form <key>=<value> or <key>=\"<value>\" but found: '{0}'")]
68 MalformedContentDispositionEntries(String),
69 #[error("Requires empty line in single multipart after Content-Disposition and other headers before the body begins!")]
72 SingleMultipartMissingEmptyLine,
73 #[error("Multipart should be ended with boundary '{0}'. End of file encountered instead.")]
74 MultipartShouldBeEndedWithBoundary(String),
75 #[error("Boundary within multipart content type is required to be 1-70 characters long.")]
76 InvalidMultipartBoundaryLength,
77 #[error("Invalid character: '{0}' found in multipart boundary.")]
78 InvalidMultipartBoundaryCharacter(String),
79 #[error("Content disposition header of a multipart (multipart/formdata) requires a name field, found only {0}")]
80 SingleMultipartNameMissing(String),
81 #[error("Expected closing '%}}' characters for response handler when opened with '{{%', response handler script is malformed.")]
83 MissingResponseHandlerClose,
84
85 #[error("Missing filepath for response after redirecting file using '>>', or '>>!'")]
86 MissingResponseOutputPath,
87
88 #[error("Could not import collection")]
89 ImportCollectionError,
90
91 #[error("unknown parse error")]
93 Unknown,
94}
95
96#[derive(Debug, PartialEq, Clone)]
97pub struct ParseErrorDetails {
98 pub error: ParseError,
99 pub details: Option<String>,
100 pub start_pos: Option<usize>,
101 pub end_pos: Option<usize>,
102}
103
104impl Default for ParseErrorDetails {
105 fn default() -> Self {
106 ParseErrorDetails {
107 error: ParseError::Unknown,
108 details: None,
109 start_pos: None,
110 end_pos: None,
111 }
112 }
113}
114
115impl ParseErrorDetails {
116 pub fn new_with_position(error: ParseError, position: (usize, Option<usize>)) -> Self {
117 ParseErrorDetails {
118 error,
119 details: None,
120 start_pos: Some(position.0),
121 end_pos: position.1,
122 }
123 }
124}
125
126impl From<ParseError> for ParseErrorDetails {
127 fn from(parse_error: ParseError) -> Self {
128 ParseErrorDetails {
129 error: parse_error,
130 ..Default::default()
131 }
132 }
133}
134
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136#[derive(Error, Debug, PartialEq, Eq)]
137pub enum SerializeError {
138 #[error("IoError occurred during serialization: {0}")]
139 IoError(String),
140}
141
142#[derive(Debug, PartialEq)]
143pub struct ErrorWithPartial {
144 pub partial_request: PartialRequest,
145 pub details: Vec<ParseErrorDetails>,
146}