@@ -172,6 +172,85 @@ describe('GET /api/proxy', () => {
172172 } ) ;
173173 } ) ;
174174
175+ it ( 'returns 400 for invalid structured proxy request JSON' , async ( ) => {
176+ const request = new Request ( 'http://localhost/api/proxy' , {
177+ method : 'POST' ,
178+ headers : { 'content-type' : 'application/json' } ,
179+ body : '{not-json' ,
180+ } ) ;
181+
182+ const response = await POST ( request ) ;
183+
184+ expect ( response . status ) . toBe ( 400 ) ;
185+ expect ( await response . json ( ) ) . toEqual ( { error : 'Invalid proxy request body' } ) ;
186+ } ) ;
187+
188+ it ( 'returns 400 for malformed structured proxy requests' , async ( ) => {
189+ const request = new Request ( 'http://localhost/api/proxy' , {
190+ method : 'POST' ,
191+ headers : { 'content-type' : 'application/json' } ,
192+ body : JSON . stringify ( {
193+ url : 'https://api.example.com/items' ,
194+ headers : {
195+ accept : 42 ,
196+ } ,
197+ } ) ,
198+ } ) ;
199+
200+ const response = await POST ( request ) ;
201+
202+ expect ( response . status ) . toBe ( 400 ) ;
203+ expect ( await response . json ( ) ) . toEqual ( { error : 'Invalid proxy request body' } ) ;
204+ } ) ;
205+
206+ it ( 'rejects oversized structured request bodies before fetching' , async ( ) => {
207+ const request = new Request ( 'http://localhost/api/proxy' , {
208+ method : 'POST' ,
209+ headers : { 'content-type' : 'application/json' } ,
210+ body : JSON . stringify ( {
211+ url : 'https://api.example.com/items' ,
212+ method : 'POST' ,
213+ body : 'x' . repeat ( 1024 * 1024 + 1 ) ,
214+ } ) ,
215+ } ) ;
216+
217+ const response = await POST ( request ) ;
218+
219+ expect ( response . status ) . toBe ( 400 ) ;
220+ expect ( await response . json ( ) ) . toEqual ( { error : 'Request body is too large' } ) ;
221+ expect ( mockFetch ) . not . toHaveBeenCalled ( ) ;
222+ } ) ;
223+
224+ it ( 'returns 502 with response body when the remote server fails' , async ( ) => {
225+ mockFetch . mockResolvedValueOnce (
226+ new Response ( '{"error":"upstream"}' , {
227+ status : 503 ,
228+ statusText : 'Service Unavailable' ,
229+ } ) ,
230+ ) ;
231+ const request = new Request ( 'http://localhost/api/proxy?url=https://api.example.com/data' ) ;
232+
233+ const response = await GET ( request ) ;
234+
235+ expect ( response . status ) . toBe ( 502 ) ;
236+ expect ( await response . json ( ) ) . toEqual ( {
237+ error : 'Remote request failed: 503 Service Unavailable' ,
238+ body : '{"error":"upstream"}' ,
239+ } ) ;
240+ } ) ;
241+
242+ it ( 'returns 502 when a redirect is missing its location header' , async ( ) => {
243+ mockFetch . mockResolvedValueOnce ( new Response ( null , { status : 302 } ) ) ;
244+ const request = new Request ( 'http://localhost/api/proxy?url=https://api.example.com/data' ) ;
245+
246+ const response = await GET ( request ) ;
247+
248+ expect ( response . status ) . toBe ( 502 ) ;
249+ expect ( await response . json ( ) ) . toEqual ( {
250+ error : 'Unable to fetch URL: Remote server returned a redirect without a location' ,
251+ } ) ;
252+ } ) ;
253+
175254 it ( 'returns the underlying network error code for failed requests' , async ( ) => {
176255 mockFetch . mockRejectedValueOnce (
177256 new Error ( 'fetch failed' , {
0 commit comments