Fixup for requests with paths containing escaped slashes

This commit is contained in:
rfm 2025-02-14 12:34:07 +00:00
parent b641bf1e99
commit d1d5552dfb
6 changed files with 73 additions and 14 deletions

View file

@ -1,3 +1,15 @@
2025-01-14 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/GNUstepBase/NSURL+GNUstepBase.h:
* Source/GSHTTPURLHandle.m:
* Source/NSURL.m:
* Source/NSURLProtocol.m:
* Tests/base/NSURL/basic.m:
Fix -pathWithEscapes to return the full path as documented.
Change NSURLHandle/NSURLConnection to use this method (rather than
-fullPath) so that %2f escape sequences are preserved in the path
in the outgoing request (and also when used as a cache key).
2025-01-10 Richard Frith-Macdonald <rfm@gnu.org>
* ChangeLog: Update for new release

View file

@ -58,7 +58,8 @@ extern "C" {
@end
@interface NSURL (GNUstepBase)
/** Returns the full path for this URL including any trailing slash.
/** Returns the full path for this URL including any trailing slash but
* without escapes.
*/
- (NSString*) fullPath;
@ -66,7 +67,7 @@ extern "C" {
* This is useful if you need to distinguish between "/" and "%2F" in the path.
* The normal -path method will convert all "%2F" value in the path into "/"
* so that you have no way of knowing whether a "/" is part of a path component
* ir is a path separator.
* or is a path separator.
*/
- (NSString*) pathWithEscapes;
@end

View file

@ -573,8 +573,8 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
}
auth = [authentication authorizationForAuthentication: nil
method: method
path: [u fullPath]];
method: method
path: [u pathWithEscapes]];
/* If authentication is nil then auth will also be nil
*/
if (auth != nil)
@ -893,7 +893,7 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
auth = [authentication authorizationForAuthentication: ac
method: method
path: [url fullPath]];
path: [url pathWithEscapes]];
if (auth != nil)
{
[self writeProperty: auth forKey: @"Authorization"];
@ -1101,8 +1101,7 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
/*
* Set up request - differs for proxy version unless tunneling via ssl.
*/
path = [[[u fullPath] stringByTrimmingSpaces]
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
path = [[u pathWithEscapes] stringByTrimmingSpaces];
if ([path length] == 0)
{
path = @"/";
@ -1923,8 +1922,7 @@ debugWrite(GSHTTPURLHandle *handle, NSData *data)
method = @"GET";
}
}
path = [[[u fullPath] stringByTrimmingSpaces]
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
path = [[u pathWithEscapes] stringByTrimmingSpaces];
if ([path length] == 0)
{
path = @"/";

View file

@ -2161,7 +2161,41 @@ static NSUInteger urlAlign;
- (NSString*) pathWithEscapes
{
return [self _pathWithEscapes: YES];
NSString *path = nil;
if (YES == myData->isGeneric || 0 == myData->scheme)
{
unsigned int len = 3;
if (_baseURL != nil)
{
if (baseData->path && *baseData->path)
{
len += strlen(baseData->path);
}
else if (baseData->hasNoPath == NO)
{
len++;
}
}
if (myData->path && *myData->path)
{
len += strlen(myData->path);
}
else if (myData->hasNoPath == NO)
{
len++;
}
if (len > 3)
{
char buf[len];
char *ptr;
ptr = [self _path: buf withEscapes: YES];
path = [NSString stringWithUTF8String: ptr];
}
}
return path;
}
@end

View file

@ -871,7 +871,7 @@ typedef struct {
/* Perform a redirect if the path is empty.
* As per MacOs-X documentation.
*/
if ([[[this->request URL] fullPath] length] == 0)
if ([[[this->request URL] pathWithEscapes] length] == 0)
{
NSString *s = [[this->request URL] absoluteString];
NSURL *url;
@ -1413,7 +1413,7 @@ typedef struct {
auth = [authentication
authorizationForAuthentication: hdr
method: [this->request HTTPMethod]
path: [url fullPath]];
path: [url pathWithEscapes]];
}
if (auth == nil)
@ -1813,8 +1813,7 @@ typedef struct {
dataUsingEncoding: NSASCIIStringEncoding]];
[m appendBytes: " " length: 1];
u = [this->request URL];
s = [[u fullPath] stringByAddingPercentEscapesUsingEncoding:
NSUTF8StringEncoding];
s = [u pathWithEscapes];
if ([s hasPrefix: @"/"] == NO)
{
[m appendBytes: "/" length: 1];

View file

@ -3,6 +3,7 @@
#import "ObjectTesting.h"
#if GNUSTEP
#import <GNUstepBase/NSURL+GNUstepBase.h>
extern const char *GSPathHandling(const char *);
#endif
@ -166,6 +167,20 @@ int main()
#if GNUSTEP
PASS_EQUAL([rel fullPath], @"/testing/aaa/bbb/ccc/",
"Simple relative URL fullPath works");
PASS_EQUAL([rel pathWithEscapes], @"/testing/aaa/bbb/ccc/",
"Simple relative URL pathWithEscapes works");
#endif
rel = [NSURL URLWithString: @"aaa%2fbbb%2fccc/" relativeToURL: url];
PASS_EQUAL([rel absoluteString],
@"http://here.and.there/testing/aaa%2fbbb%2fccc/",
"Escaped relative URL absoluteString works");
PASS_EQUAL([rel path], @"/testing/aaa/bbb/ccc",
"Escaped relative URL path works");
#if GNUSTEP
PASS_EQUAL([rel fullPath], @"/testing/aaa/bbb/ccc/",
"Escaped relative URL fullPath works");
PASS_EQUAL([rel pathWithEscapes], @"/testing/aaa%2fbbb%2fccc/",
"Escaped relative URL pathWithEscapes works");
#endif
url = [NSURL URLWithString: @"http://1.2.3.4/a?b;foo"];