@@ -368,6 +368,150 @@ describe('RawBytesFetch', () => {
368368 ) ;
369369 expect ( decodedRequestBody ) . toEqual ( encodedBodyBytes ) ;
370370 } ) ;
371+
372+ it ( 'parseHttpRequest should handle a path and query string' , async ( ) => {
373+ const requestBytes = `GET /core/version-check/1.7/?channel=beta HTTP/1.1\r\nHost: playground.internal\r\n\r\n` ;
374+ const request = await RawBytesFetch . parseHttpRequest (
375+ new ReadableStream ( {
376+ start ( controller ) {
377+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
378+ controller . close ( ) ;
379+ } ,
380+ } ) ,
381+ 'playground.internal' ,
382+ 'http'
383+ ) ;
384+ expect ( request . url ) . toEqual (
385+ 'http://playground.internal/core/version-check/1.7/?channel=beta'
386+ ) ;
387+ } ) ;
388+
389+ it ( 'parseHttpRequest should handle a simple path without query string' , async ( ) => {
390+ const requestBytes = `GET /api/users HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
391+ const request = await RawBytesFetch . parseHttpRequest (
392+ new ReadableStream ( {
393+ start ( controller ) {
394+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
395+ controller . close ( ) ;
396+ } ,
397+ } ) ,
398+ 'example.com' ,
399+ 'http'
400+ ) ;
401+ expect ( request . url ) . toEqual ( 'http://example.com/api/users' ) ;
402+ } ) ;
403+
404+ it ( 'parseHttpRequest should handle root path' , async ( ) => {
405+ const requestBytes = `GET / HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
406+ const request = await RawBytesFetch . parseHttpRequest (
407+ new ReadableStream ( {
408+ start ( controller ) {
409+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
410+ controller . close ( ) ;
411+ } ,
412+ } ) ,
413+ 'example.com' ,
414+ 'https'
415+ ) ;
416+ expect ( request . url ) . toEqual ( 'https://example.com/' ) ;
417+ } ) ;
418+
419+ it ( 'parseHttpRequest should handle URL-encoded characters in path' , async ( ) => {
420+ const requestBytes = `GET /search/hello%20world HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
421+ const request = await RawBytesFetch . parseHttpRequest (
422+ new ReadableStream ( {
423+ start ( controller ) {
424+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
425+ controller . close ( ) ;
426+ } ,
427+ } ) ,
428+ 'example.com' ,
429+ 'http'
430+ ) ;
431+ expect ( request . url ) . toEqual ( 'http://example.com/search/hello%20world' ) ;
432+ } ) ;
433+
434+ it ( 'parseHttpRequest should handle URL-encoded characters in query string' , async ( ) => {
435+ const requestBytes = `GET /search?q=hello+world&filter=a%26b HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
436+ const request = await RawBytesFetch . parseHttpRequest (
437+ new ReadableStream ( {
438+ start ( controller ) {
439+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
440+ controller . close ( ) ;
441+ } ,
442+ } ) ,
443+ 'example.com' ,
444+ 'http'
445+ ) ;
446+ expect ( request . url ) . toEqual (
447+ 'http://example.com/search?q=hello+world&filter=a%26b'
448+ ) ;
449+ } ) ;
450+
451+ it ( 'parseHttpRequest should handle empty query parameter values' , async ( ) => {
452+ const requestBytes = `GET /api?key1=&key2=value2 HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
453+ const request = await RawBytesFetch . parseHttpRequest (
454+ new ReadableStream ( {
455+ start ( controller ) {
456+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
457+ controller . close ( ) ;
458+ } ,
459+ } ) ,
460+ 'example.com' ,
461+ 'http'
462+ ) ;
463+ expect ( request . url ) . toEqual ( 'http://example.com/api?key1=&key2=value2' ) ;
464+ } ) ;
465+
466+ it ( 'parseHttpRequest should handle path with hash fragment' , async ( ) => {
467+ // Note: Hash fragments are typically not sent in HTTP requests,
468+ // but if they are, the URL constructor should handle them
469+ const requestBytes = `GET /page#section HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
470+ const request = await RawBytesFetch . parseHttpRequest (
471+ new ReadableStream ( {
472+ start ( controller ) {
473+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
474+ controller . close ( ) ;
475+ } ,
476+ } ) ,
477+ 'example.com' ,
478+ 'http'
479+ ) ;
480+ expect ( request . url ) . toEqual ( 'http://example.com/page#section' ) ;
481+ } ) ;
482+
483+ it ( 'parseHttpRequest should handle path with query and hash' , async ( ) => {
484+ const requestBytes = `GET /page?param=value#section HTTP/1.1\r\nHost: example.com\r\n\r\n` ;
485+ const request = await RawBytesFetch . parseHttpRequest (
486+ new ReadableStream ( {
487+ start ( controller ) {
488+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
489+ controller . close ( ) ;
490+ } ,
491+ } ) ,
492+ 'example.com' ,
493+ 'http'
494+ ) ;
495+ expect ( request . url ) . toEqual (
496+ 'http://example.com/page?param=value#section'
497+ ) ;
498+ } ) ;
499+
500+ it ( 'parseHttpRequest should preserve Host header over default host' , async ( ) => {
501+ const requestBytes = `GET /api HTTP/1.1\r\nHost: custom.host.com\r\n\r\n` ;
502+ const request = await RawBytesFetch . parseHttpRequest (
503+ new ReadableStream ( {
504+ start ( controller ) {
505+ controller . enqueue ( new TextEncoder ( ) . encode ( requestBytes ) ) ;
506+ controller . close ( ) ;
507+ } ,
508+ } ) ,
509+ 'default.host.com' , // Different from Host header
510+ 'https'
511+ ) ;
512+ // Should use the Host header, not the default host parameter
513+ expect ( request . url ) . toEqual ( 'https://custom.host.com/api' ) ;
514+ } ) ;
371515} ) ;
372516
373517type MakeRequestOptions = {
0 commit comments