@@ -17,12 +17,12 @@ import (
1717
1818// APIError represents an api error response.
1919type APIError struct {
20- StatusCode int `json:"status_code"` // HTTP status code
21- Method string `json:"method"` // HTTP method used for the request
22- URL string `json:"url"` // The URL of the HTTP request
23- Message string `json:"message"` // Summary of the error
24- Details []string `json:"details"` // Detailed error messages, if any
25- RawResponse string `json:"raw_response"` // Raw response body for debugging
20+ StatusCode int `json:"status_code"` // HTTP status code
21+ Method string `json:"method"` // HTTP method used for the request
22+ URL string `json:"url"` // The URL of the HTTP request
23+ Message string `json:"message"` // Summary of the error
24+ Details []string `json:"details,omitempty"` // Detailed error messages, if any
25+ RawResponse string `json:"raw_response"` // Raw response body for debugging
2626}
2727
2828// Error returns a string representation of the APIError, making it compatible with the error interface.
@@ -166,59 +166,71 @@ func parseTextResponse(bodyBytes []byte, apiError *APIError, log logger.Logger,
166166 )
167167}
168168
169- // parseHTMLResponse extracts meaningful information from an HTML error response and concatenates all text within <p> tags.
169+ // parseHTMLResponse extracts meaningful information from an HTML error response,
170+ // concatenating all text within <p> tags and links found within them.
170171func parseHTMLResponse (bodyBytes []byte , apiError * APIError , log logger.Logger , resp * http.Response ) {
171- // Always set the Raw field to the entire HTML content for debugging purposes.
172+ // Set the entire HTML content as the RawResponse for debugging purposes.
172173 apiError .RawResponse = string (bodyBytes )
173174
175+ // Parse the HTML document.
174176 reader := bytes .NewReader (bodyBytes )
175177 doc , err := html .Parse (reader )
176178 if err != nil {
177179 log .LogError ("html_parsing_error" , resp .Request .Method , resp .Request .URL .String (), apiError .StatusCode , resp .Status , err , apiError .RawResponse )
178180 return
179181 }
180182
181- var messages []string // To accumulate messages from all <p> tags .
183+ var messages []string // To accumulate messages and links .
182184 var parse func (* html.Node )
183185 parse = func (n * html.Node ) {
184186 if n .Type == html .ElementNode && n .Data == "p" {
185- var pText strings.Builder
187+ var pContent strings.Builder
186188 for c := n .FirstChild ; c != nil ; c = c .NextSibling {
187- if c .Type == html .TextNode && strings .TrimSpace (c .Data ) != "" {
188- // Build text content of <p> tag.
189- if pText .Len () > 0 {
190- pText .WriteString (" " ) // Add a space between text nodes within the same <p> tag.
189+ if c .Type == html .TextNode {
190+ // Append text content directly.
191+ pContent .WriteString (strings .TrimSpace (c .Data ) + " " )
192+ } else if c .Type == html .ElementNode && c .Data == "a" {
193+ // Extract href attribute value for links.
194+ var href string
195+ for _ , attr := range c .Attr {
196+ if attr .Key == "href" {
197+ href = attr .Val
198+ break
199+ }
200+ }
201+ if href != "" {
202+ // Append the link to the pContent builder.
203+ pContent .WriteString (fmt .Sprintf ("[Link: %s] " , href ))
191204 }
192- pText .WriteString (strings .TrimSpace (c .Data ))
193205 }
194206 }
195- if pText .Len () > 0 {
196- // Add the built text content of the <p> tag to messages.
197- messages = append (messages , pText .String ())
207+ finalContent := strings .TrimSpace (pContent .String ())
208+ if finalContent != "" {
209+ // Add the content of the <p> tag to messages.
210+ messages = append (messages , finalContent )
198211 }
199212 }
200213 for c := n .FirstChild ; c != nil ; c = c .NextSibling {
201- parse (c ) // Recursively parse the document.
214+ parse (c ) // Continue traversing the document.
202215 }
203216 }
204217
205- parse (doc )
218+ parse (doc ) // Start parsing the document.
206219
207- // Concatenate all accumulated messages with a separator.
220+ // Concatenate all accumulated messages and links with a separator.
208221 if len (messages ) > 0 {
209222 apiError .Message = strings .Join (messages , "; " )
210223 } else {
211- // Fallback error message if no specific messages were extracted.
224+ // Fallback error message if no specific content was extracted.
212225 apiError .Message = "HTML Error: See 'Raw' field for details."
213226 }
214227
215- // Determine the error to log based on whether a message was found.
228+ // Determine the error to log based on whether content was found.
216229 var logErr error
217230 if apiError .Message == "" {
218231 logErr = fmt .Errorf ("no error message extracted from HTML" )
219232 }
220233
221- // Log the extracted error message or the fallback message using the centralized logger.
234+ // Log the extracted content or the fallback message using the centralized logger.
222235 log .LogError ("html_error_detected" , resp .Request .Method , resp .Request .URL .String (), apiError .StatusCode , resp .Status , logErr , apiError .RawResponse )
223-
224236}
0 commit comments