I got a call the other day from an engineer at Apple who found a fun
bug in iDisk: their WebDAV server reads the PUT Content-length into,
yes, a 32-bit signed int, so the only way to send files bigger than
2G is to use Transfer-encoding: chunked. I don't know if y'all have
any interest in adding a proper chunked PUT implementation into neon,
but here's some code for the curious. The only change to neon was
making a req->body_length of -1 signal indeterminate length: I added
a conditional if ( length >= 0 ) in set_body_length() to suppress
adding the content-length header, and I changed the two instances of
req->body_length > 0 in send_request() to req->body_length != 0.
Here's the data provider callback:
struct uploadData
{
WebDAVConnectionWorker* worker;
off_t size;
off_t offset;
int fd;
BOOL done;
};
ssize_t
provideChunkedUpload(void *userdata, char *buffer, size_t buflen)
{
struct uploadData* data = (struct uploadData*)userdata;
if ( buflen == 0 || data->done )
return 0;
// neon doesn't know the total size, so we have to call our
progress callback by hand
neon_progress_proc(data->worker, data->offset, data->size);
int len = buflen - 10; // leave room for 6 hex digits and 2
CRLFs
if ( len > data->size - data->offset )
len = data->size - data->offset;
// write hex chunk size
int count = snprintf(buffer, buflen, "%x", len);
// write CRLF
buffer[count++] = '\r';
buffer[count++] = '\n';
if ( len > 0 )
{
// write file data
int ret = read(data->fd, buffer + count, len);
if ( ret < 0 )
return ret;
data->offset += ret;
count += ret;
}
else
data->done = YES;
// write CRLF
buffer[count++] = '\r';
buffer[count++] = '\n';
return count;
}
And the calling code, adapted from ne_put():
// Use chunked encoding instead
ne_request *req = ne_request_create(session, "PUT", cpath);
ne_add_request_header(req, "Transfer-Encoding", "chunked");
ne_lock_using_resource(req, cpath, 0);
ne_lock_using_parent(req, cpath);
struct stat st;
if ( fstat(fd, &st) != 0 )
{
NSLog(@"couldn't stat file");
return NO;
}
struct uploadData data = { self, st.st_size, 0, fd, NO };
ne_set_request_body_provider(req, -1, provideChunkedUpload, (void*)
&data);
err = ne_request_dispatch(req);
Chunked encoding allows for more headers after the body, so a proper
implementation could add a content length or MD5 sum at the end..
Hope this is useful for someone.
-Dave
Panic, Inc.
_______________________________________________
neon mailing list
[email protected]
http://mailman.webdav.org/mailman/listinfo/neon