Browse Source

feat: fix HTTP/1.0 protocol handling in shoprenter-proxy #55

- Changed from HTTP/1.1 to HTTP/1.0 protocol (ShopRenter API requirement)
- Fixed request format: proper double CRLF after headers before body
- Enhanced response parsing: supports both \r\n\r\n and \n\n separators
- Added detailed logging for debugging (first 500 chars of response)
- Updated all log messages to reference [HTTP/1.0] instead of [HTTP/1.1]

This fixes the "no header/body separator found" error when proxying
requests from n8n to ShopRenter API.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Claude 5 months ago
parent
commit
9517058e37
1 changed files with 34 additions and 21 deletions
  1. 34 21
      supabase/functions/shoprenter-proxy/index.ts

+ 34 - 21
supabase/functions/shoprenter-proxy/index.ts

@@ -24,8 +24,8 @@ const corsHeaders = {
  */
  */
 
 
 /**
 /**
- * Makes an HTTP/1.1 request using raw TCP/TLS connection
- * This is necessary because ShopRenter API works with HTTP/1.1
+ * Makes an HTTP/1.0 request using raw TCP/TLS connection
+ * This is necessary because ShopRenter API requires HTTP/1.0
  * and Deno's fetch API uses HTTP/2 which causes connection issues
  * and Deno's fetch API uses HTTP/2 which causes connection issues
  */
  */
 async function makeHttp11Request(
 async function makeHttp11Request(
@@ -42,9 +42,9 @@ async function makeHttp11Request(
   })
   })
 
 
   try {
   try {
-    // Build HTTP/1.1 request
+    // Build HTTP/1.0 request (ShopRenter requires HTTP/1.0)
     const requestLines: string[] = [
     const requestLines: string[] = [
-      `${method} ${path} HTTP/1.1`,
+      `${method} ${path} HTTP/1.0`,
       `Host: ${hostname}`,
       `Host: ${hostname}`,
     ]
     ]
 
 
@@ -53,20 +53,22 @@ async function makeHttp11Request(
       requestLines.push(`${key}: ${value}`)
       requestLines.push(`${key}: ${value}`)
     }
     }
 
 
-    // Add Connection: close for HTTP/1.1
+    // Add Connection: close for HTTP/1.0
     requestLines.push('Connection: close')
     requestLines.push('Connection: close')
 
 
     // Empty line to end headers
     // Empty line to end headers
     requestLines.push('')
     requestLines.push('')
+    requestLines.push('')
+
+    // Build the complete request
+    let request = requestLines.join('\r\n')
 
 
-    // Add body if present
+    // Add body if present (after the double CRLF)
     if (body) {
     if (body) {
-      requestLines.push(body)
+      request = request + body
     }
     }
 
 
-    const request = requestLines.join('\r\n')
-
-    console.log('[HTTP/1.1] Sending request:', request.split('\r\n').slice(0, 10).join('\n'))
+    console.log('[HTTP/1.0] Sending request:', request.split('\r\n').slice(0, 10).join('\n'))
 
 
     // Send request
     // Send request
     const encoder = new TextEncoder()
     const encoder = new TextEncoder()
@@ -87,30 +89,41 @@ async function makeHttp11Request(
         // This is expected when server sends Connection: close
         // This is expected when server sends Connection: close
         if (e instanceof Deno.errors.UnexpectedEof ||
         if (e instanceof Deno.errors.UnexpectedEof ||
             (e instanceof Error && e.name === 'UnexpectedEof')) {
             (e instanceof Error && e.name === 'UnexpectedEof')) {
-          console.log('[HTTP/1.1] Connection closed by server (expected with Connection: close)')
+          console.log('[HTTP/1.0] Connection closed by server (expected with Connection: close)')
           break
           break
         }
         }
         throw e
         throw e
       }
       }
     }
     }
 
 
-    console.log('[HTTP/1.1] Received response length:', responseData.length)
+    console.log('[HTTP/1.0] Received response length:', responseData.length)
+    console.log('[HTTP/1.0] First 500 chars:', responseData.substring(0, 500))
+
+    // Parse HTTP response - try both \r\n\r\n and \n\n separators
+    let headerEndIndex = responseData.indexOf('\r\n\r\n')
+    let headerSeparator = '\r\n\r\n'
+
+    if (headerEndIndex === -1) {
+      // Try Unix-style line endings
+      headerEndIndex = responseData.indexOf('\n\n')
+      headerSeparator = '\n\n'
+    }
 
 
-    // Parse HTTP response
-    const headerEndIndex = responseData.indexOf('\r\n\r\n')
     if (headerEndIndex === -1) {
     if (headerEndIndex === -1) {
+      console.error('[HTTP/1.0] Could not find header separator. Response data:', responseData.substring(0, 200))
       throw new Error('Invalid HTTP response: no header/body separator found')
       throw new Error('Invalid HTTP response: no header/body separator found')
     }
     }
 
 
     const headerSection = responseData.substring(0, headerEndIndex)
     const headerSection = responseData.substring(0, headerEndIndex)
-    const bodySection = responseData.substring(headerEndIndex + 4)
+    const bodySection = responseData.substring(headerEndIndex + headerSeparator.length)
 
 
     // Parse status line
     // Parse status line
-    const lines = headerSection.split('\r\n')
+    const lines = headerSection.split(/\r?\n/)
     const statusLine = lines[0]
     const statusLine = lines[0]
     const statusMatch = statusLine.match(/HTTP\/1\.[01]\s+(\d+)\s+(.*)/)
     const statusMatch = statusLine.match(/HTTP\/1\.[01]\s+(\d+)\s+(.*)/)
 
 
     if (!statusMatch) {
     if (!statusMatch) {
+      console.error('[HTTP/1.0] Invalid status line:', statusLine)
       throw new Error(`Invalid HTTP status line: ${statusLine}`)
       throw new Error(`Invalid HTTP status line: ${statusLine}`)
     }
     }
 
 
@@ -128,7 +141,7 @@ async function makeHttp11Request(
       }
       }
     }
     }
 
 
-    console.log('[HTTP/1.1] Response received:', status, statusText)
+    console.log('[HTTP/1.0] Response received:', status, statusText)
 
 
     return {
     return {
       status,
       status,
@@ -144,9 +157,9 @@ async function makeHttp11Request(
       // UnexpectedEof during close means server already closed the connection
       // UnexpectedEof during close means server already closed the connection
       if (e instanceof Deno.errors.UnexpectedEof ||
       if (e instanceof Deno.errors.UnexpectedEof ||
           (e instanceof Error && e.name === 'UnexpectedEof')) {
           (e instanceof Error && e.name === 'UnexpectedEof')) {
-        console.log('[HTTP/1.1] Connection already closed by server')
+        console.log('[HTTP/1.0] Connection already closed by server')
       } else {
       } else {
-        console.error('[HTTP/1.1] Error closing connection:', e)
+        console.error('[HTTP/1.0] Error closing connection:', e)
       }
       }
     }
     }
   }
   }
@@ -272,9 +285,9 @@ serve(async (req) => {
       }
       }
     }
     }
 
 
-    console.log(`[ShopRenter Proxy] Making HTTP/1.1 request to: ${hostname}${fullPath}`)
+    console.log(`[ShopRenter Proxy] Making HTTP/1.0 request to: ${hostname}${fullPath}`)
 
 
-    // Make HTTP/1.1 request using raw TCP/TLS connection
+    // Make HTTP/1.0 request using raw TCP/TLS connection
     const shopRenterResponse = await makeHttp11Request(
     const shopRenterResponse = await makeHttp11Request(
       hostname,
       hostname,
       fullPath,
       fullPath,