Skip to content

Commit a038558

Browse files
committed
Fix. call all callback from coroutine where perform was called.
1 parent f42a0e4 commit a038558

File tree

7 files changed

+169
-7
lines changed

7 files changed

+169
-7
lines changed

src/lceasy.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ int lcurl_easy_create(lua_State *L, int error_mode){
4141

4242
p->err_mode = error_mode;
4343
if(!p->curl) return lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_EASY, CURLE_FAILED_INIT);
44-
p->L = L;
44+
45+
p->magic = LCURL_EASY_MAGIC;
46+
p->L = NULL;
47+
p->post = NULL;
4548
p->storage = lcurl_storage_init(L);
4649
p->wr.cb_ref = p->wr.ud_ref = LUA_NOREF;
4750
p->rd.cb_ref = p->rd.ud_ref = LUA_NOREF;
@@ -115,6 +118,12 @@ static int lcurl_easy_perform(lua_State *L){
115118

116119
assert(p->rbuffer.ref == LUA_NOREF);
117120

121+
// store reference to current coroutine to callbacks
122+
p->L = L;
123+
if(p->post){
124+
p->post->L = L;
125+
}
126+
118127
code = curl_easy_perform(p->curl);
119128

120129
if(p->rbuffer.ref != LUA_NOREF){
@@ -308,6 +317,8 @@ static int lcurl_easy_set_HTTPPOST(lua_State *L){
308317
curl_easy_setopt(p->curl, CURLOPT_READFUNCTION, lcurl_hpost_read_callback);
309318
}
310319

320+
p->post = post;
321+
311322
lua_settop(L, 1);
312323
return 1;
313324
}
@@ -420,6 +431,8 @@ static int lcurl_easy_unset_HTTPPOST(lua_State *L){
420431
lcurl_storage_remove_i(L, p->storage, CURLOPT_HTTPPOST);
421432
}
422433

434+
p->post = NULL;
435+
423436
lua_settop(L, 1);
424437
return 1;
425438
}
@@ -758,12 +771,15 @@ static size_t lcurl_read_callback(lua_State *L,
758771

759772
static size_t lcurl_easy_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
760773
lcurl_easy_t *p = arg;
774+
if(p->magic == LCURL_HPOST_STREAM_MAGIC){
775+
return lcurl_hpost_read_callback(buffer, size, nitems, arg);
776+
}
761777
return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
762778
}
763779

764780
static size_t lcurl_hpost_read_callback(char *buffer, size_t size, size_t nitems, void *arg){
765781
lcurl_hpost_stream_t *p = arg;
766-
return lcurl_read_callback(p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
782+
return lcurl_read_callback(*p->L, &p->rd, &p->rbuffer, buffer, size, nitems);
767783
}
768784

769785
static int lcurl_easy_set_READFUNCTION(lua_State *L){

src/lceasy.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,19 @@ enum {
3232
#undef LCURL_LNG_INDEX
3333
#undef OPT_ENTRY
3434

35+
#define LCURL_EASY_MAGIC 0xEA
36+
37+
typedef struct lcurl_hpost_tag lcurl_hpost_t;
38+
3539
typedef struct lcurl_easy_tag{
40+
unsigned char magic;
41+
3642
lua_State *L;
3743
lcurl_callback_t rd;
3844
lcurl_read_buffer_t rbuffer;
3945

46+
lcurl_hpost_t *post;
47+
4048
CURL *curl;
4149
int storage;
4250
int lists[LCURL_LIST_COUNT];

src/lchttppost.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ static lcurl_hpost_stream_t *lcurl_hpost_stream_add(lua_State *L, lcurl_hpost_t
2323
lcurl_hpost_stream_t *stream = malloc(sizeof(lcurl_hpost_stream_t));
2424
if(!stream) return NULL;
2525

26-
stream->L = L;
26+
stream->magic = LCURL_HPOST_STREAM_MAGIC;
27+
stream->L = &p->L;
2728
stream->rbuffer.ref = LUA_NOREF;
2829
stream->rd.cb_ref = stream->rd.ud_ref = LUA_NOREF;
2930
stream->next = NULL;

src/lchttppost.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@
1515
#include "lcutils.h"
1616
#include <stdlib.h>
1717

18+
#define LCURL_HPOST_STREAM_MAGIC 0xAA
19+
1820
typedef struct lcurl_hpost_stream_tag{
19-
lua_State *L;
21+
unsigned char magic;
22+
23+
lua_State **L;
2024
lcurl_callback_t rd;
2125
lcurl_read_buffer_t rbuffer;
2226
struct lcurl_hpost_stream_tag *next;
2327
}lcurl_hpost_stream_t;
2428

2529
typedef struct lcurl_hpost_tag{
30+
lua_State *L;
2631
struct curl_httppost *post;
2732
struct curl_httppost *last;
2833
int storage;

src/lcmulti.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,21 @@ static int lcurl_multi_perform(lua_State *L){
118118
lcurl_multi_t *p = lcurl_getmulti(L);
119119
int running_handles = 0;
120120
CURLMcode code;
121+
122+
lua_settop(L, 1);
123+
lua_rawgeti(L, LCURL_LUA_REGISTRY, p->h_ref);
124+
lua_pushnil(L);
125+
while(lua_next(L, 2)){
126+
lcurl_easy_t *e = lcurl_geteasy_at(L, -1);
127+
e->L = L;
128+
if(e->post){
129+
e->post->L = L;
130+
}
131+
lua_pop(L, 1);
132+
}
133+
134+
lua_settop(L, 1);
135+
121136
while((code = curl_multi_perform(p->curl, &running_handles)) == CURLM_CALL_MULTI_PERFORM);
122137
if(code != CURLM_OK){
123138
lcurl_fail_ex(L, p->err_mode, LCURL_ERROR_MULTI, code);

test/test_curl.lua

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ function test_add_handle()
6363
end
6464
end
6565

66-
m = assert_equal(m, m:add_handle(next_easy()))
66+
assert_equal(m, m:add_handle(next_easy()))
6767

6868
for data, type, easy in m:iperform() do
6969

test/test_easy.lua

Lines changed: 119 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@ local function strem(ch, n, m)
6464
return n, get_bin_by( (ch):rep(n), m)
6565
end
6666

67+
local function Stream(ch, n, m)
68+
local size, reader
69+
70+
local _stream = {}
71+
72+
function _stream:read(...)
73+
_stream.called_ctx = self
74+
_stream.called_co = coroutine.running()
75+
return reader(...)
76+
end
77+
78+
function _stream:size()
79+
return size
80+
end
81+
82+
function _stream:reset()
83+
size, reader = strem(ch, n, m)
84+
return self
85+
end
86+
87+
return _stream:reset()
88+
end
89+
6790
local ENABLE = true
6891

6992
local _ENV = TEST_CASE'write_callback' if ENABLE then
@@ -165,6 +188,31 @@ function test_write_pass_03()
165188
assert_equal(c, c:perform())
166189
end
167190

191+
function test_write_coro()
192+
local co1, co2
193+
local called
194+
195+
co1 = coroutine.create(function()
196+
c = assert(curl.easy{
197+
url = url;
198+
writefunction = function()
199+
called = coroutine.running()
200+
return true
201+
end
202+
})
203+
coroutine.yield()
204+
end)
205+
206+
co2 = coroutine.create(function()
207+
assert_equal(c, c:perform())
208+
end)
209+
210+
coroutine.resume(co1)
211+
coroutine.resume(co2)
212+
213+
assert_equal(co2, called)
214+
end
215+
168216
end
169217

170218
local _ENV = TEST_CASE'progress_callback' if ENABLE then
@@ -380,7 +428,7 @@ local _ENV = TEST_CASE'read_stream_callback' if ENABLE and is_curl_ge(7,30,0) th
380428

381429
local url = "http://httpbin.org/post"
382430

383-
local c, f, t
431+
local m, c, f, t
384432

385433
local function json_data()
386434
return json.decode(table.concat(t))
@@ -399,17 +447,86 @@ end
399447
function teardown()
400448
if f then f:free() end
401449
if c then c:close() end
402-
t, f, c = nil
450+
if m then m:close() end
451+
t, f, c, m = nil
403452
end
404453

405454
function test()
406455
assert_equal(f, f:add_stream('SSSSS', strem('X', 128, 13)))
407456
assert_equal(c, c:setopt_httppost(f))
457+
458+
-- should be called only stream callback
459+
local read_called
460+
assert_equal(c, c:setopt_readfunction(function()
461+
read_called = true
462+
end))
463+
464+
assert_equal(c, c:perform())
465+
466+
assert_nil(read_called)
467+
468+
assert_equal(200, c:getinfo_response_code())
469+
local data = assert_table(json_data())
470+
assert_table(data.form)
471+
assert_equal(('X'):rep(128), data.form.SSSSS)
472+
end
473+
474+
function test_object()
475+
local s = Stream('X', 128, 13)
476+
477+
assert_equal(f, f:add_stream('SSSSS', s:size(), s))
478+
assert_equal(c, c:setopt_httppost(f))
408479
assert_equal(c, c:perform())
480+
481+
assert_equal(s, s.called_ctx)
482+
483+
assert_equal(200, c:getinfo_response_code())
484+
local data = assert_table(json_data())
485+
assert_table(data.form)
486+
assert_equal(('X'):rep(128), data.form.SSSSS)
487+
end
488+
489+
function test_co_multi()
490+
local s = Stream('X', 128, 13)
491+
assert_equal(f, f:add_stream('SSSSS', s:size(), s))
492+
assert_equal(c, c:setopt_httppost(f))
493+
494+
m = assert(scurl.multi())
495+
assert_equal(m, m:add_handle(c))
496+
497+
co = coroutine.create(function()
498+
while 1== m:perform() do end
499+
end)
500+
501+
coroutine.resume(co)
502+
503+
assert_equal(co, s.called_co)
504+
505+
assert_equal(200, c:getinfo_response_code())
506+
local data = assert_table(json_data())
507+
assert_table(data.form)
508+
assert_equal(('X'):rep(128), data.form.SSSSS)
509+
end
510+
511+
function test_co()
512+
local s = Stream('X', 128, 13)
513+
514+
assert_equal(f, f:add_stream('SSSSS', s:size(), s))
515+
assert_equal(c, c:setopt_httppost(f))
516+
517+
co = coroutine.create(function()
518+
assert_equal(c, c:perform())
519+
end)
520+
521+
coroutine.resume(co)
522+
523+
assert_equal(co, s.called_co)
524+
409525
assert_equal(200, c:getinfo_response_code())
410526
local data = assert_table(json_data())
411527
assert_table(data.form)
412528
assert_equal(('X'):rep(128), data.form.SSSSS)
529+
413530
end
414531

415532
function test_abort_01()

0 commit comments

Comments
 (0)