summaryrefslogtreecommitdiff
path: root/inc/private.h
blob: 1264aa2313b22f16ddb92c27130cb6b2de059fa1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/** **************************************************************************
 * private.h
 * 
 * Copyright 2008 Bryan Ischo <bryan@ischo.com>
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the
 *
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 ************************************************************************** **/

#ifndef PRIVATE_H
#define PRIVATE_H

#include <curl/curl.h>
#include <curl/multi.h>
#include "libs3.h"


// As specified in S3 documntation
#define META_HEADER_NAME_PREFIX "x-amz-meta-"
#define HOSTNAME "s3.amazonaws.com"


// Derived from S3 documentation

// This is the maximum number of x-amz-meta- headers that could be included in
// a request to S3.  The smallest meta header is" x-amz-meta-n: v".  Since S3
// doesn't count the ": " against the total, the smallest amount of data to
// count for a header would be the length of "x-amz-meta-nv".
#define MAX_META_HEADER_COUNT \
    (S3_MAX_META_HEADER_SIZE / (sizeof(META_HEADER_NAME_PREFIX "nv") - 1))

// This is the maximum number of bytes needed in a "compacted meta header"
// buffer, which is a buffer storing all of the compacted meta headers.
#define COMPACTED_META_HEADER_BUFFER_SIZE \
    (MAX_META_HEADER_COUNT * sizeof(META_HEADER_NAME_PREFIX "n: v"))

// Maximum url encoded key size; since every single character could require
// URL encoding, it's 3 times the size of a key (since each url encoded
// character takes 3 characters: %NN)
#define MAX_URLENCODED_KEY_SIZE (3 * S3_MAX_KEY_SIZE)

// This is the maximum size of a URI that could be passed to S3:
// https://s3.amazonaws.com/${BUCKET}/${KEY}?acl
// 255 is the maximum bucket length
#define MAX_URI_SIZE \
    ((sizeof("https://" HOSTNAME "/") - 1) + 255 + 1 + \
     MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent" - 1)) + 1)

// Maximum size of a canonicalized resource
#define MAX_CANONICALIZED_RESOURCE_SIZE \
    (1 + 255 + 1 + MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent") - 1) + 1)


// Describes a type of HTTP request (these are our supported HTTP "verbs")
typedef enum
{
    HttpRequestTypeGET,
    HttpRequestTypeHEAD,
    HttpRequestTypePUT,
    HttpRequestTypeCOPY,
    HttpRequestTypeDELETE
} HttpRequestType;


// This completely describes a request.  A RequestParams is not required to be
// allocated from the heap and its lifetime is not assumed to extend beyond
// the lifetime of the function to which it has been passed.
typedef struct RequestParams
{
    // The following are supplied ---------------------------------------------

    // Request type, affects the HTTP verb used
    HttpRequestType httpRequestType;
    // Protocol to use for request
    S3Protocol protocol;
    // URI style to use for request
    S3UriStyle uriStyle;
    // Bucket name, if any
    const char *bucketName;
    // Key, if any
    const char *key;
    // Query params - ready to append to URI (i.e. ?p1=v1?p2=v2)
    const char *queryParams;
    // sub resource, like ?acl, ?location, ?torrent
    const char *subResource;
    // AWS Access Key ID
    const char *accessKeyId;
    // AWS Secret Access Key
    const char *secretAccessKey;
    // Request headers
    const S3RequestHeaders *requestHeaders;
    // Response handler callback
    S3ResponseHandler *handler;
    // The callbacks to make for the data payload of the response
    union {
        S3ListServiceCallback *listServiceCallback;
        S3ListBucketCallback *listBucketCallback;
        S3PutObjectCallback *putObjectCallback;
        S3GetObjectCallback *getObjectCallback;
    } u;
    // Response handler callback data
    void *callbackData;
    // The write callback to be called by curl, if needed; req will be passed
    // in as the Request structure for this request
    size_t (*curlWriteCallback)(void *data, size_t s, size_t n, void *req);
    // The read callback to be called by curl, if needed; req will be passed
    // in as the Request structure for this request
    size_t (*curlReadCallback)(void *data, size_t s, size_t n, void *req);
    // This is the number of bytes that will be provided by the read callback,
    // if the read callback is set
    int64_t readSize;
    

    // The following are computed ---------------------------------------------

    // All x-amz- headers, in normalized form (i.e. NAME: VALUE, no other ws)
    char *amzHeaders[MAX_META_HEADER_COUNT + 2]; // + 2 for acl and date
    // The number of x-amz- headers
    int amzHeadersCount;
    // Storage for amzHeaders (the +256 is for x-amz-acl and x-amz-date)
    char amzHeadersRaw[COMPACTED_META_HEADER_BUFFER_SIZE + 256 + 1];
    // Canonicalized x-amz- headers
    char canonicalizedAmzHeaders[COMPACTED_META_HEADER_BUFFER_SIZE + 256 + 1];
    // URL-Encoded key
    char urlEncodedKey[MAX_URLENCODED_KEY_SIZE + 1];
    // Canonicalized resource
    char canonicalizedResource[MAX_CANONICALIZED_RESOURCE_SIZE + 1];
    // Cache-Control header (or empty)
    char cacheControlHeader[128];
    // Content-Type header (or empty)
    char contentTypeHeader[128];
    // Content-MD5 header (or empty)
    char md5Header[128];
    // Content-Disposition header (or empty)
    char contentDispositionHeader[128];
    // Content-Encoding header (or empty)
    char contentEncodingHeader[128];
    // Expires header (or empty)
    char expiresHeader[128];
    // Authorization header
    char authorizationHeader[128];
} RequestParams;


// This is the stuff associated with a request that needs to be on the heap
// (and thus live while a curl_multi is in use).
typedef struct Request
{
    // True if this request has already been used
    int used;

    // The CURL structure driving the request
    CURL *curl;

    // The HTTP headers to use for the curl request
    struct curl_slist *headers;

    // libcurl requires that the uri be stored outside of the curl handle
    char uri[MAX_URI_SIZE + 1];

    // The callback data to pass to all of the callbacks
    void *callbackData;

    // responseHeaders.{requestId,requestId2,contentType,server,eTag} get
    // copied into here.  We allow 128 bytes for each header, plus \0 term.
    char responseHeaderStrings[5 * 129];

    // The length thus far of responseHeaderStrings
    int responseHeaderStringsLen;

    // responseHeaders.lastModified will be set to this if there is a
    // LastModified header
    struct timeval lastModified;

    // responseHeaders.metaHeaders strings get copied into here
    char responseMetaHeaderStrings[COMPACTED_META_HEADER_BUFFER_SIZE];

    // The length thus far of metaHeaderStrings
    int responseMetaHeaderStringsLen;

    // Response meta headers
    S3MetaHeader responseMetaHeaders[MAX_META_HEADER_COUNT];

    // Callback stuff ---------------------------------------------------------

    // Callback to make when headers are available
    S3ResponseHeadersCallback *headersCallback;

    // The structure to pass to the headers callback
    S3ResponseHeaders responseHeaders;

    // This is set to nonzero after the haders callback has been made
    int headersCallbackMade;

    // This is the write callback that the user of the request wants to have
    // called back when data is available.
    size_t (*curlWriteCallback)(void *data, size_t s, size_t n, void *req);

    // This is the read callback that the user of the request wants to have
    // called back when data is to be written.
    size_t (*curlReadCallback)(void *data, size_t s, size_t n, void *req);

    // The callback to make when the response has been completely handled
    S3ResponseCompleteCallback *completeCallback;

    // This will be 0 if S3 didn't send any XML error
    int receivedS3Error;

    // If S3 did send an XML error, this is the parsed form of it
    S3Error s3Error;

    // The callbacks to make for the data payload of the response
    union {
        S3ListServiceCallback *listServiceCallback;
        S3ListBucketCallback *listBucketCallback;
        S3PutObjectCallback *putObjectCallback;
        S3GetObjectCallback *getObjectCallback;
    } u;
} Request;


struct S3RequestContext
{
    CURLM *curlm;

    int count;
};


// Mutex functions ------------------------------------------------------------

// Create a mutex.  Returns 0 if none could be created.
struct S3Mutex *mutex_create();

// Lock a mutex
void mutex_lock(struct S3Mutex *mutex);

// Unlock a mutex
void mutex_unlock(struct S3Mutex *mutex);

// Destroy a mutex
void mutex_destroy(struct S3Mutex *mutex);


// Request functions
// ------------------------------------------------------

// Initialize the API
S3Status request_api_initialize(const char *userAgentInfo);

// Deinitialize the API
void request_api_deinitialize();

// Perform a request; if context is 0, performs the request immediately;
// otherwise, sets it up to be performed by context.  If S3StatusOK is
// returned, the request was successfully completed/added to the context.
// Otherwise, it was never even started due to an error with the request.
S3Status request_perform(RequestParams *params, S3RequestContext *context);

// Called by the internal request code or internal request context code when a
// curl has finished the request
void request_finish(Request *request, S3Status status);


#endif /* PRIVATE_H */