Skip to content

Commit f5d2f7c

Browse files
committed
now upload APIs could switch upHosts
1 parent e4a1aea commit f5d2f7c

21 files changed

+476
-239
lines changed

.github/workflows/ci.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
run: |
2121
set -e
2222
cmake -S . -B build
23-
cmake --build build
23+
cmake --build build -j $(nproc)
2424
- name: Unit test
2525
working-directory: '${{ github.workspace }}/build/gtests'
2626
run: |
@@ -38,7 +38,7 @@ jobs:
3838
run: |
3939
set -e
4040
cmake -DOPENSSL_ROOT_DIR="$(brew --prefix)/opt/openssl/" -S . -B build
41-
cmake --build build
41+
cmake --build build -j $(nproc)
4242
- name: Unit test
4343
working-directory: '${{ github.workspace }}/build/gtests'
4444
run: |

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
## CHANGE LOG
22

3+
## v7.8.0
4+
5+
- 支持缓存多个 `v4/query` 查询结果
6+
- 上传重试支持切换上传域名
7+
38
## v7.7.0 (2023-12-25)
49

510
- 支持归档直读存储类型

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ CMAKE_POLICY(SET CMP0074 NEW)
88
SET(PROJECT_NAME qiniu)
99

1010
# 建立项目
11-
PROJECT(${PROJECT_NAME} VERSION 7.7.0 LANGUAGES C)
11+
PROJECT(${PROJECT_NAME} VERSION 7.8.0 LANGUAGES C)
1212

1313
set(CMAKE_C_STANDARD 99)
1414

docs/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ INCLUDE(FetchContent)
7777
FetchContent_Declare(
7878
qiniu
7979
GIT_REPOSITORY https://github.com/qiniu/c-sdk.git
80-
GIT_TAG v7.7.0
80+
GIT_TAG v7.8.0
8181
)
8282
FetchContent_MakeAvailable(qiniu)
8383

qiniu/base.c

+12
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,18 @@ void Qiniu_FreeV2(void **addr)
3131
*addr = NULL;
3232
}
3333
}
34+
void Qiniu_Multi_Free(int n, ...)
35+
{
36+
void *p = NULL;
37+
va_list v1;
38+
va_start(v1, n);
39+
for (int i = 0; i < n; i++)
40+
{
41+
p = va_arg(v1, void *);
42+
free(p);
43+
}
44+
va_end(v1);
45+
}
3446

3547
/*============================================================================*/
3648
/* type Qiniu_Count */

qiniu/base.h

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ typedef unsigned long long Qiniu_Uint64;
110110

111111
QINIU_DLLAPI extern void Qiniu_Free(void *addr);
112112
QINIU_DLLAPI extern void Qiniu_FreeV2(void **addr);
113+
QINIU_DLLAPI extern void Qiniu_Multi_Free(int n, ...);
113114
/*============================================================================*/
114115
/* type Qiniu_Count */
115116

qiniu/code.c

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#include <curl/curl.h>
2+
#include "private/code.h"
3+
4+
Qiniu_Retry_Decision _Qiniu_Should_Retry(int code)
5+
{
6+
if (code / 100 == 4 && code != 406 && code != 429)
7+
{
8+
return QINIU_DONT_RETRY;
9+
}
10+
switch (code)
11+
{
12+
case CURLE_COULDNT_RESOLVE_HOST:
13+
case CURLE_COULDNT_CONNECT:
14+
case CURLE_WEIRD_SERVER_REPLY:
15+
case CURLE_PARTIAL_FILE:
16+
case CURLE_UPLOAD_FAILED:
17+
case CURLE_OPERATION_TIMEDOUT:
18+
case CURLE_SSL_CONNECT_ERROR:
19+
case CURLE_SEND_ERROR:
20+
case CURLE_RECV_ERROR:
21+
case CURLE_SSL_CERTPROBLEM:
22+
case CURLE_SSL_CIPHER:
23+
case CURLE_PEER_FAILED_VERIFICATION:
24+
case CURLE_HTTP2_STREAM:
25+
case CURLE_HTTP3:
26+
case CURLE_QUIC_CONNECT_ERROR:
27+
case 406:
28+
case 429:
29+
case 500:
30+
case 502:
31+
case 503:
32+
case 504:
33+
case 509:
34+
case 571:
35+
case 573:
36+
case 599:
37+
return QINIU_TRY_NEXT_DOMAIN;
38+
39+
default:
40+
return QINIU_DONT_RETRY;
41+
}
42+
}

qiniu/http.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ void Qiniu_Client_InitEx(Qiniu_Client *self, Qiniu_Auth auth, size_t bufSize)
348348
Qiniu_Zero_Ptr(self);
349349
self->curl = curl_easy_init();
350350
self->auth = auth;
351+
self->retriesMax = SIZE_MAX;
351352

352353
Qiniu_Buffer_Init(&self->b, bufSize);
353354
Qiniu_Buffer_Init(&self->respHeader, bufSize);
@@ -396,6 +397,11 @@ void Qiniu_Client_SetLowSpeedLimit(Qiniu_Client *self, long lowSpeedLimit, long
396397
self->lowSpeedTime = lowSpeedTime;
397398
} // Qiniu_Client_SetLowSpeedLimit
398399

400+
void Qiniu_Client_SetMaximumRetries(Qiniu_Client *self, size_t retriesMax)
401+
{
402+
self->retriesMax = retriesMax;
403+
} // Qiniu_Client_SetMaximumRetries
404+
399405
void Qiniu_Client_SetTimeout(Qiniu_Client *self, long timeoutMs)
400406
{
401407
self->timeoutMs = timeoutMs;
@@ -475,7 +481,7 @@ static Qiniu_Error Qiniu_Client_callWithBody(
475481
Qiniu_Error err;
476482
const char *ctxType;
477483
char ctxLength[64], userAgent[64];
478-
Qiniu_Header *headers = NULL;
484+
Qiniu_Header *headers;
479485
CURL *curl = (CURL *)self->curl;
480486
err = Qiniu_Client_config(self);
481487
if (err.code != Qiniu_OK.code)

qiniu/http.h

+4
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,17 @@ extern "C"
139139

140140
// Millisecond timeout for the connection phase.
141141
long connectTimeoutMs;
142+
143+
// Max retries count.
144+
size_t retriesMax;
142145
};
143146
typedef struct _Qiniu_Client Qiniu_Client;
144147

145148
QINIU_DLLAPI extern void Qiniu_Client_InitEx(Qiniu_Client *self, Qiniu_Auth auth, size_t bufSize);
146149
QINIU_DLLAPI extern void Qiniu_Client_Cleanup(Qiniu_Client *self);
147150
QINIU_DLLAPI extern void Qiniu_Client_BindNic(Qiniu_Client *self, const char *nic);
148151
QINIU_DLLAPI extern void Qiniu_Client_SetLowSpeedLimit(Qiniu_Client *self, long lowSpeedLimit, long lowSpeedTime);
152+
QINIU_DLLAPI extern void Qiniu_Client_SetMaximumRetries(Qiniu_Client *self, size_t retries);
149153
QINIU_DLLAPI extern void Qiniu_Client_SetTimeout(Qiniu_Client *self, long timeoutMs);
150154
QINIU_DLLAPI extern void Qiniu_Client_SetConnectTimeout(Qiniu_Client *self, long connectTimeoutMs);
151155
QINIU_DLLAPI extern void Qiniu_Client_EnableAutoQuery(Qiniu_Client *self, Qiniu_Bool useHttps);

qiniu/io.c

+87-54
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "reader.h"
1212
#include "recorder_utils.h"
1313
#include "private/region.h"
14+
#include "private/code.h"
1415
#include <curl/curl.h>
1516

1617
/*============================================================================*/
@@ -58,20 +59,27 @@ CURL *Qiniu_Client_reset(Qiniu_Client *self);
5859

5960
Qiniu_Error Qiniu_callex(CURL *curl, Qiniu_Buffer *resp, Qiniu_Json **ret, Qiniu_Bool simpleError, Qiniu_Buffer *resph);
6061

61-
static Qiniu_Error Get_Qiniu_UpHost(Qiniu_Client *client, const char *accessKey, const char *bucketName, Qiniu_Io_PutExtra *extra, const char **upHost)
62+
static Qiniu_Error Get_Qiniu_UpHosts(Qiniu_Client *client, const char *accessKey, const char *bucketName, Qiniu_Io_PutExtra *extra, const char *const **upHosts, size_t *upHostsCount)
6263
{
6364
if (extra && extra->ipCount != 0)
6465
{
6566
Qiniu_Count oldIndex = Qiniu_Count_Inc(&extra->ipIndex);
66-
*upHost = extra->upIps[abs(oldIndex % extra->ipCount)];
67+
*upHosts = &extra->upIps[labs(oldIndex % extra->ipCount)];
68+
*upHostsCount = 1;
6769
}
6870
else if (extra && extra->upHost != NULL)
6971
{
70-
*upHost = extra->upHost;
72+
*upHosts = &extra->upHost;
73+
*upHostsCount = 1;
74+
}
75+
else if (extra && extra->upHosts != NULL && extra->upHostsCount != 0)
76+
{
77+
*upHosts = extra->upHosts;
78+
*upHostsCount = extra->upHostsCount;
7179
}
7280
else
7381
{
74-
Qiniu_Error err = _Qiniu_Region_Get_Up_Host(client, accessKey, bucketName, upHost);
82+
Qiniu_Error err = _Qiniu_Region_Get_Up_Hosts(client, accessKey, bucketName, upHosts, upHostsCount);
7583
if (err.code != Qiniu_OK.code)
7684
{
7785
return err;
@@ -150,48 +158,61 @@ static Qiniu_Error Qiniu_Io_call(
150158
{
151159
int retCode = 0;
152160
Qiniu_Error err;
153-
struct curl_slist *headers = NULL;
154-
const char *upHost = NULL;
161+
struct curl_slist *headers;
162+
const char *const *upHosts;
163+
const char *defaultUpHosts[] = {QINIU_UP_HOST};
164+
size_t upHostsCount;
155165

156-
err = Qiniu_Client_config(self);
166+
headers = curl_slist_append(NULL, "Expect:");
167+
err = Get_Qiniu_UpHosts(self, accessKey, bucketName, extra, &upHosts, &upHostsCount);
157168
if (err.code != Qiniu_OK.code)
158169
{
159170
return err;
160171
}
161-
err = Get_Qiniu_UpHost(self, accessKey, bucketName, extra, &upHost);
162-
if (err.code != Qiniu_OK.code)
172+
if (upHostsCount == 0)
163173
{
164-
return err;
174+
upHosts = defaultUpHosts;
175+
upHostsCount = 1;
165176
}
166177

167-
headers = curl_slist_append(NULL, "Expect:");
168-
169-
CURL *curl = Qiniu_Client_reset(self);
170-
curl_easy_setopt(curl, CURLOPT_URL, upHost);
171-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
172-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
173-
174-
//// For aborting uploading file.
175-
if (extra->upAbortCallback)
178+
for (size_t retries = 0; retries < upHostsCount && retries <= self->retriesMax; retries++)
176179
{
177-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, Qiniu_Rd_Reader_Callback);
178-
} // if
180+
CURL *curl = Qiniu_Client_reset(self);
181+
err = Qiniu_Client_config(self);
182+
if (err.code != Qiniu_OK.code)
183+
{
184+
return err;
185+
}
186+
curl_easy_setopt(curl, CURLOPT_URL, upHosts[retries]);
187+
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
188+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
179189

180-
err = Qiniu_callex(curl, &self->b, &self->root, Qiniu_False, &self->respHeader);
181-
if (err.code == Qiniu_OK.code && ret != NULL)
182-
{
183-
if (extra->callbackRetParser != NULL)
190+
//// For aborting uploading file.
191+
if (extra->upAbortCallback)
184192
{
185-
err = (*extra->callbackRetParser)(extra->callbackRet, self->root);
193+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, Qiniu_Rd_Reader_Callback);
194+
} // if
195+
196+
err = Qiniu_callex(curl, &self->b, &self->root, Qiniu_False, &self->respHeader);
197+
if (err.code == Qiniu_OK.code)
198+
{
199+
if (extra->callbackRetParser != NULL)
200+
{
201+
err = (*extra->callbackRetParser)(extra->callbackRet, self->root);
202+
}
203+
else if (ret != NULL)
204+
{
205+
ret->hash = Qiniu_Json_GetString(self->root, "hash", NULL);
206+
ret->key = Qiniu_Json_GetString(self->root, "key", NULL);
207+
ret->persistentId = Qiniu_Json_GetString(self->root, "persistentId", NULL);
208+
}
209+
break;
186210
}
187-
else
211+
else if (_Qiniu_Should_Retry(err.code) == QINIU_DONT_RETRY)
188212
{
189-
ret->hash = Qiniu_Json_GetString(self->root, "hash", NULL);
190-
ret->key = Qiniu_Json_GetString(self->root, "key", NULL);
191-
ret->persistentId = Qiniu_Json_GetString(self->root, "persistentId", NULL);
213+
break;
192214
}
193215
}
194-
195216
curl_formfree(formpost);
196217
curl_slist_free_all(headers);
197218
return err;
@@ -313,7 +334,6 @@ Qiniu_Error Qiniu_Io_PutBuffer(
313334
CURLFORM_BUFFER, key, CURLFORM_BUFFERPTR, buf, CURLFORM_BUFFERLENGTH, fsize, CURLFORM_END);
314335
err = Qiniu_Io_call(self, accessKey, bucketName, ret, form.formpost, extra);
315336

316-
error:
317337
Qiniu_Free((void *)accessKey);
318338
Qiniu_Free((void *)bucketName);
319339
return err;
@@ -327,42 +347,56 @@ static Qiniu_Error Qiniu_Io_call_with_callback(
327347
{
328348
int retCode = 0;
329349
Qiniu_Error err;
330-
struct curl_slist *headers = NULL;
331-
const char *upHost;
350+
struct curl_slist *headers;
351+
const char *const *upHosts;
352+
const char *defaultUpHosts[] = {QINIU_UP_HOST};
353+
size_t upHostsCount;
332354

333-
CURL *curl = Qiniu_Client_reset(self);
334-
err = Qiniu_Client_config(self);
355+
headers = curl_slist_append(NULL, "Expect:");
356+
err = Get_Qiniu_UpHosts(self, accessKey, bucketName, extra, &upHosts, &upHostsCount);
335357
if (err.code != Qiniu_OK.code)
336358
{
337359
return err;
338360
}
339-
err = Get_Qiniu_UpHost(self, accessKey, bucketName, extra, &upHost);
340-
if (err.code != Qiniu_OK.code)
361+
if (upHostsCount == 0)
341362
{
342-
return err;
363+
upHosts = defaultUpHosts;
364+
upHostsCount = 1;
343365
}
344366

345-
headers = curl_slist_append(NULL, "Expect:");
367+
for (size_t retries = 0; retries < upHostsCount && retries <= self->retriesMax; retries++)
368+
{
369+
CURL *curl = Qiniu_Client_reset(self);
370+
err = Qiniu_Client_config(self);
371+
if (err.code != Qiniu_OK.code)
372+
{
373+
return err;
374+
}
346375

347-
curl_easy_setopt(curl, CURLOPT_URL, upHost);
348-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
349-
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
350-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, rdr);
376+
curl_easy_setopt(curl, CURLOPT_URL, upHosts[retries]);
377+
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
378+
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
379+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, rdr);
351380

352-
err = Qiniu_callex(curl, &self->b, &self->root, Qiniu_False, &self->respHeader);
353-
if (err.code == Qiniu_OK.code && ret != NULL)
354-
{
355-
if (extra->callbackRetParser != NULL)
381+
err = Qiniu_callex(curl, &self->b, &self->root, Qiniu_False, &self->respHeader);
382+
if (err.code == Qiniu_OK.code)
356383
{
357-
err = (*extra->callbackRetParser)(extra->callbackRet, self->root);
384+
if (extra->callbackRetParser != NULL)
385+
{
386+
err = (*extra->callbackRetParser)(extra->callbackRet, self->root);
387+
}
388+
else if (ret != NULL)
389+
{
390+
ret->hash = Qiniu_Json_GetString(self->root, "hash", NULL);
391+
ret->key = Qiniu_Json_GetString(self->root, "key", NULL);
392+
}
393+
break;
358394
}
359-
else
395+
else if (_Qiniu_Should_Retry(err.code) == QINIU_DONT_RETRY)
360396
{
361-
ret->hash = Qiniu_Json_GetString(self->root, "hash", NULL);
362-
ret->key = Qiniu_Json_GetString(self->root, "key", NULL);
397+
break;
363398
}
364399
}
365-
366400
curl_formfree(formpost);
367401
curl_slist_free_all(headers);
368402
return err;
@@ -408,7 +442,6 @@ Qiniu_Error Qiniu_Io_PutStream(
408442
CURLFORM_END);
409443

410444
err = Qiniu_Io_call_with_callback(self, accessKey, bucketName, ret, form.formpost, rdr, extra);
411-
error:
412445
Qiniu_Free((void *)accessKey);
413446
Qiniu_Free((void *)bucketName);
414447
return err;

0 commit comments

Comments
 (0)