-
Notifications
You must be signed in to change notification settings - Fork 593
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
1. new parameter "enableRedirect" for hs.http.doAsyncRequest 2. add 5 tests to test this change pr-feature
- Loading branch information
Showing
4 changed files
with
250 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// | ||
// HShttp.m | ||
// Hammerspoon | ||
// | ||
// Created by Alex Chen on 08/21/2022. | ||
|
||
#import "HSTestCase.h" | ||
|
||
@interface HThttp : HSTestCase | ||
|
||
@end | ||
|
||
@implementation HThttp | ||
|
||
- (void)setUp { | ||
[super setUpWithRequire:@"test_http"]; | ||
// Put setup code here. This method is called before the invocation of each test method in the class. | ||
} | ||
|
||
- (void)tearDown { | ||
// Put teardown code here. This method is called after the invocation of each test method in the class. | ||
[super tearDown]; | ||
} | ||
|
||
// Http tests | ||
|
||
- (void)testHttpDoAsyncRequestWithCachePolicyParam { | ||
RUN_TWO_PART_LUA_TEST_WITH_TIMEOUT(5) | ||
} | ||
|
||
- (void)testHttpDoAsyncRequestWithRedirectParamButNoCachePolicyParam { | ||
RUN_LUA_TEST() | ||
} | ||
|
||
- (void)testHttpDoAsyncRequestWithNoEnableRedirectParam { | ||
RUN_TWO_PART_LUA_TEST_WITH_TIMEOUT(5) | ||
} | ||
|
||
- (void)testHttpDoAsyncRequestWithRedirection { | ||
RUN_TWO_PART_LUA_TEST_WITH_TIMEOUT(5) | ||
} | ||
|
||
- (void)testHttpDoAsyncRequestWithoutRedirection { | ||
RUN_TWO_PART_LUA_TEST_WITH_TIMEOUT(5) | ||
} | ||
|
||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,6 +23,7 @@ static id responseBodyToId(NSHTTPURLResponse *httpResponse, NSData *bodyData) { | |
// Definition of the collection delegate to receive callbacks from NSUrlConnection | ||
@interface connectionDelegate : NSObject<NSURLConnectionDelegate> | ||
@property int fn; | ||
@property bool enableRedirect; | ||
@property(nonatomic, retain) NSMutableData* receivedData; | ||
@property(nonatomic, retain) NSHTTPURLResponse* httpResponse; | ||
@property(nonatomic, retain) NSURLConnection* connection; | ||
|
@@ -96,6 +97,37 @@ - (void)connection:(NSURLConnection * __unused)connection didFailWithError:(NSEr | |
_lua_stackguard_exit(skin.L); | ||
} | ||
|
||
- (NSURLRequest *)connection:(NSURLConnection *)connection | ||
willSendRequest:(NSURLRequest *)request | ||
redirectResponse:(NSURLResponse *)response { | ||
|
||
if (self.fn == LUA_NOREF) { | ||
return nil; | ||
} | ||
|
||
if ([response isKindOfClass:[NSHTTPURLResponse class]] && self.enableRedirect == false) { | ||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response; | ||
|
||
LuaSkin *skin = [LuaSkin sharedWithState:NULL]; | ||
lua_State *L = skin.L; | ||
_lua_stackguard_entry(L); | ||
|
||
[skin pushLuaRef:refTable ref:self.fn]; | ||
lua_pushinteger(L, (int)httpResponse.statusCode); | ||
[skin pushNSObject:responseBodyToId(self.httpResponse, self.receivedData)]; | ||
[skin pushNSObject:httpResponse.allHeaderFields]; | ||
[skin protectedCallAndError:@"hs.http connectionDelefate:didFinishLoading during redirection" nargs:3 nresults:0]; | ||
|
||
remove_delegate(L, self); | ||
_lua_stackguard_exit(L); | ||
|
||
[connection cancel]; | ||
return nil; | ||
} | ||
|
||
return request; | ||
} | ||
|
||
@end | ||
|
||
// If the user specified a request body, get it from stack, | ||
|
@@ -166,7 +198,7 @@ static void extractHeadersFromStack(lua_State* L, int index, NSMutableURLRequest | |
} | ||
} | ||
|
||
/// hs.http.doAsyncRequest(url, method, data, headers, callback, [cachePolicy]) | ||
/// hs.http.doAsyncRequest(url, method, data, headers, callback, [cachePolicy], [enableRedirect]) | ||
/// Function | ||
/// Creates an HTTP request and executes it asynchronously | ||
/// | ||
|
@@ -180,22 +212,29 @@ static void extractHeadersFromStack(lua_State* L, int index, NSMutableURLRequest | |
/// * body - A string containing the body of the response | ||
/// * headers - A table containing the HTTP headers of the response | ||
/// * cachePolicy - An optional string containing the cache policy ("protocolCachePolicy", "ignoreLocalCache", "ignoreLocalAndRemoteCache", "returnCacheOrLoad", "returnCacheDontLoad" or "reloadRevalidatingCache"). Defaults to `protocolCachePolicy`. | ||
/// * enableRedirect - An optional boolean to indicate whether to redirect the http request. Defaults to true. | ||
/// | ||
/// Returns: | ||
/// * None | ||
/// | ||
/// Notes: | ||
/// * If authentication is required in order to download the request, the required credentials must be specified as part of the URL (e.g. "http://user:[email protected]/"). If authentication fails, or credentials are missing, the connection will attempt to continue without credentials. | ||
/// * If the Content-Type response header begins `text/` then the response body return value is a UTF8 string. Any other content type passes the response body, unaltered, as a stream of bytes. | ||
/// * If enableRedirect is given, cachePolicy parameter can't be omitted or set to nil. If enableRedirect is set to true, response body will be empty string. This seems the limitation of 'connection:willSendRequest:redirectResponse' method. | ||
static int http_doAsyncRequest(lua_State* L){ | ||
LuaSkin *skin = [LuaSkin sharedWithState:L]; | ||
[skin checkArgs:LS_TSTRING, LS_TSTRING, LS_TSTRING|LS_TNIL, LS_TTABLE|LS_TNIL, LS_TFUNCTION, LS_TSTRING | LS_TOPTIONAL, LS_TBREAK]; | ||
[skin checkArgs:LS_TSTRING, LS_TSTRING, LS_TSTRING|LS_TNIL, LS_TTABLE|LS_TNIL, LS_TFUNCTION, LS_TSTRING | LS_TOPTIONAL, LS_TBOOLEAN | LS_TOPTIONAL, LS_TBREAK]; | ||
|
||
NSString* cachePolicy = nil; | ||
if (lua_type(L, 6) == LUA_TSTRING) { | ||
cachePolicy = [skin toNSObjectAtIndex:6]; | ||
} | ||
|
||
bool enableRedirect = true; | ||
if (lua_type(L, 7) == LUA_TBOOLEAN) { | ||
enableRedirect = lua_toboolean(L, 7); | ||
} | ||
|
||
NSMutableURLRequest* request = getRequestFromStack(L, cachePolicy); | ||
getBodyFromStack(L, 3, request); | ||
extractHeadersFromStack(L, 4, request); | ||
|
@@ -204,6 +243,8 @@ static int http_doAsyncRequest(lua_State* L){ | |
lua_pushvalue(L, 5); | ||
|
||
connectionDelegate* delegate = [[connectionDelegate alloc] init]; | ||
delegate.enableRedirect = enableRedirect; | ||
|
||
delegate.receivedData = [[NSMutableData alloc] init]; | ||
delegate.fn = [skin luaRef:refTable]; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
-- hs.http = require("hs.http") | ||
-- hs = require("hs") | ||
|
||
_G["respCode"] = 0 | ||
_G["respBody"] = "" | ||
_G["respHeaders"] = {} | ||
|
||
_G["callback"] = function(code, body, headers) | ||
_G["respCode"] = code | ||
_G["respBody"] = body | ||
_G["respHeaders"] = headers | ||
end | ||
|
||
-- check error should happen if cachePolicy is set to nil and enableRedirect is given | ||
-- check point: pcall returns false, and error message contains "incorrect type 'nil' for argument 6 (expected string)" | ||
function testHttpDoAsyncRequestWithRedirectParamButNoCachePolicyParam() | ||
local ok, errMsg = pcall(function() | ||
hs.http.doAsyncRequest( | ||
'http://google.com', | ||
'GET', | ||
nil, | ||
{ ['accept-language'] = 'en', ['user-agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36', Accept = '*/*' }, | ||
_G["callback"], | ||
nil, -- this will trigger exception | ||
false | ||
) | ||
end) | ||
assertIsEqual(false, ok) | ||
print(hs.inspect(errMsg)) | ||
local startIdx, _ = string.find(errMsg, "incorrect type 'nil' for argument 6 %(expected string%)") | ||
assertGreaterThanOrEqualTo(0, startIdx) | ||
|
||
return success() | ||
end | ||
|
||
function testHttpDoAsyncRequestWithCachePolicyParamValues() | ||
if (type(_G["respCode"]) == "number" and type(_G["respBody"]) == "string" and type(_G["respHeaders"]) == "table") then | ||
-- check return code | ||
assertIsEqual(200, _G["respCode"]) | ||
assertGreaterThan(0, string.len(_G["respBody"])) | ||
return success() | ||
else | ||
return "Waiting for success..." | ||
end | ||
end | ||
|
||
-- check request should be redirected if enableRedirect is not given and cachePolicy param is given | ||
-- check point: response code == 200 | ||
function testHttpDoAsyncRequestWithCachePolicyParam() | ||
_G["respCode"] = 0 | ||
_G["respBody"] = "" | ||
_G["respHeaders"] = {} | ||
hs.http.doAsyncRequest( | ||
'http://google.com', | ||
'GET', | ||
nil, | ||
{ ['accept-language'] = 'en', ['user-agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36', Accept = '*/*' }, | ||
_G["callback"], | ||
'protocolCachePolicy' | ||
) | ||
|
||
return success() | ||
end | ||
|
||
function testHttpDoAsyncRequestWithNoEnableRedirectParamValues() | ||
if (type(_G["respCode"]) == "number" and type(_G["respBody"]) == "string" and type(_G["respHeaders"]) == "table") then | ||
-- check return code | ||
assertIsEqual(200, _G["respCode"]) | ||
assertGreaterThan(0, string.len(_G["respBody"])) | ||
return success() | ||
else | ||
return "Waiting for success..." | ||
end | ||
end | ||
|
||
-- check request should be redirected if enableRedirect param is not given. | ||
-- check point: response code == 200 | ||
function testHttpDoAsyncRequestWithNoEnableRedirectParam() | ||
_G["respCode"] = 0 | ||
_G["respBody"] = "" | ||
_G["respHeaders"] = {} | ||
hs.http.doAsyncRequest( | ||
'http://google.com', | ||
'GET', | ||
nil, | ||
{ ['accept-language'] = 'en', ['user-agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36', Accept = '*/*' }, | ||
_G["callback"] | ||
) | ||
|
||
return success() | ||
end | ||
|
||
function testHttpDoAsyncRequestWithRedirectionValues() | ||
if (type(_G["respCode"]) == "number" and type(_G["respBody"]) == "string" and type(_G["respHeaders"]) == "table") then | ||
-- check return code | ||
assertIsEqual(200, _G["respCode"]) | ||
assertGreaterThan(0, string.len(_G["respBody"])) | ||
return success() | ||
else | ||
return "Waiting for success..." | ||
end | ||
end | ||
|
||
-- check request should be redirected if enableRedirect is set to true | ||
-- check point: response code == 200 | ||
function testHttpDoAsyncRequestWithRedirection() | ||
_G["respCode"] = 0 | ||
_G["respBody"] = "" | ||
_G["respHeaders"] = {} | ||
hs.http.doAsyncRequest( | ||
'http://google.com', | ||
'GET', | ||
nil, | ||
{ ['accept-language'] = 'en', ['user-agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36', Accept = '*/*' }, | ||
_G["callback"], | ||
'protocolCachePolicy', | ||
true | ||
) | ||
|
||
return success() | ||
end | ||
|
||
function testHttpDoAsyncRequestWithoutRedirectionValues() | ||
if (type(_G["respCode"]) == "number" and type(_G["respBody"]) == "string" and type(_G["respHeaders"]) == "table") then | ||
-- check return code | ||
assertIsEqual(301, _G["respCode"]) | ||
return success() | ||
else | ||
return "Waiting for success..." | ||
end | ||
end | ||
|
||
-- check request should not be redirected if enableRedirect is set to false | ||
-- check point: response code == 301 | ||
function testHttpDoAsyncRequestWithoutRedirection() | ||
_G["respCode"] = 0 | ||
_G["respBody"] = "" | ||
_G["respHeaders"] = {} | ||
hs.http.doAsyncRequest( | ||
'http://google.com', | ||
'GET', | ||
nil, | ||
{ ['accept-language'] = 'en', ['user-agent'] = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.88 Safari/537.36', Accept = '*/*' }, | ||
_G["callback"], | ||
'protocolCachePolicy', | ||
false | ||
) | ||
|
||
return success() | ||
end |