Загрузка файла на сервер Apache в C (без веб-заголовков)
Я занимаюсь разработкой веб-сервера (Apache 2.4 в Linux) и пытаюсь поддерживать загрузку файлов со стороны клиента на сторону сервера. Мне удается получить файл на стороне сервера, но я получаю дополнительные веб-заголовки в загруженном содержимом файла, которые я хочу пропустить. Например, я при загрузке example.txt, который содержит:
I'm the file content!
В файл на стороне сервера я получаю:
------WebKitFormBoundaryqbGGz0VOmz7CVPCF
Content-Disposition: form-data; name="file"; filename="example.txt"
Content-Type: application/octet-stream
I'm the file content!
------WebKitFormBoundaryqbGGz0VOmz7CVPCF--
Фактический файл должен быть двоичным, поэтому он должен содержать точное содержимое без добавления данных.
Я использовал эти примеры: mod_upload и mod_csv.
Мой код стороны сервера:
apr_bucket_brigade* bb;
apr_bucket* b;
int status = 0;
int end = 0;
char* fname = 0;
const char* buf;
apr_size_t bytes;
char buffer[512];
apr_file_t* tmpfile;
char* tmpname = apr_pstrdup(r->pool, "/tmp/tmp-upload.XXXXXX") ;
if ( apr_file_mktemp(&tmpfile, tmpname, KEEPONCLOSE, r->pool) != APR_SUCCESS ) {
ap_remove_input_filter(r->input_filters) ;
}
apr_pool_cleanup_register(r->pool, tmpfile, (void*)apr_file_close, apr_pool_cleanup_null) ;
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
do {
status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, BLOCKSIZE) ;
if ( status == APR_SUCCESS ) {
for (b = APR_BRIGADE_FIRST(bb) ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_NEXT(b)) {
if (APR_BUCKET_IS_EOS(b)) {
end = 1;
break;
}
else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS) {
apr_file_write(tmpfile, buf, &bytes);
char* x = apr_pstrndup(r->pool, buf, bytes);
if (fname)
fname = apr_pstrcat(r->pool, fname, x, NULL);
else
fname = x;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Bucket read error") ;
}
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Brigade error") ;
}
apr_brigade_cleanup(bb);
} while ( !end && status == APR_SUCCESS );
apr_brigade_destroy(bb);
return OK;
Любые идеи, как изменить код, чтобы избежать избыточных заголовков в содержимом файла результата / любой другой способ (/ метод), чтобы получить файл на сервере?
Спасибо!
2 ответа
Итак... мое решение заключалось в том, чтобы вручную удалить эти префиксы и заголовки суффиксов. Это может помочь кому-то в будущем:
int getPrefixHeaderLength(const char* buf) {
int rows = 0;
int counter = 0;
char* ret = buf;
if (buf == NULL)
return 0;
while (*ret != 0 && rows < 4) {
if (*ret == '\n')
rows++;
ret++;
counter++;
}
return counter;
}
/* example buf: "... filename="example.txt" " */
void getFilename(const char* buf, char* filename)
{
char* pEnd = NULL;
char *pFilename = strstr(buf,"filename");
pFilename += 10;
pEnd = strchr(pFilename,'"');
snprintf(filename,pEnd-pFilename+1,"%s",pFilename);
}
apr_bucket_brigade* bb;
apr_bucket* b;
int status = 0;
int end = 0;
char* fname = 0;
const char* buf;
apr_size_t bytes;
apr_size_t totalBytes = 0;
char buffer[512];
apr_file_t* tmpfile;
const char* ctype = apr_table_get(r->headers_in, "file-0") ;
int prefixFlag = 1;
int counter = 0;
apr_off_t offsetIndex = 0;
char filename[512];
char* tmpname = apr_pstrdup(r->pool, "/tmp/tmp-upload.XXXXXX") ;
if ( apr_file_mktemp(&tmpfile, tmpname, KEEPONCLOSE, r->pool) != APR_SUCCESS ) {
ap_remove_input_filter(r->input_filters) ;
}
apr_pool_cleanup_register(r->pool, tmpfile, (void*)apr_file_close, apr_pool_cleanup_null) ;
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
do {
status = ap_get_brigade(r->input_filters, bb, AP_MODE_READBYTES, APR_BLOCK_READ, BLOCKSIZE) ;
if ( status == APR_SUCCESS ) {
for (b = APR_BRIGADE_FIRST(bb) ; b != APR_BRIGADE_SENTINEL(bb) ; b = APR_BUCKET_NEXT(b)) {
if (APR_BUCKET_IS_EOS(b)) {
end = 1;
break;
}
else if (apr_bucket_read(b, &buf, &bytes, APR_BLOCK_READ) == APR_SUCCESS) {
int prefixHeaderLength = 0;
apr_size_t sizeToWrite;
if (prefixFlag) {
if (bytes == 1) {
continue;
}
prefixHeaderLength = getPrefixHeaderLength(buf);
prefixFlag = 0;
getFilename(buf,filename);
ap_rprintf(r, "\"filename\":\"%s\",",filename);
}
//ap_rprintf(r, "\"counter%d\":%d,",counter,bytes);
sizeToWrite = bytes - prefixHeaderLength;
apr_file_write(tmpfile, buf+prefixHeaderLength, &sizeToWrite);
//ap_rprintf(r, "\"write%d\":%d,",counter,sizeToWrite);
totalBytes += bytes;
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Bucket read error") ;
}
}
}
else {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Brigade error") ;
}
apr_brigade_cleanup(bb);
counter++;
} while ( !end && status == APR_SUCCESS );
counter = 0;
while (counter < 2) {
char c;
offsetIndex = -2L;
apr_file_seek(tmpfile,SEEK_CUR, &offsetIndex);
apr_file_getc(&c,tmpfile);
if (c == '\r')
counter++;
}
apr_file_trunc(tmpfile,offsetIndex);
ap_rprintf(r, "\"size\":%d}",totalBytes);
apr_brigade_destroy(bb);
return OK;
http://apache.webthing.com/mod_upload/mod_upload.c
Вот
static void set_header(upload_ctx* ctx, const char* data)
Эта функция добавляет заголовки. Если вам не нужны заголовки, не вызывайте эту функцию в этом файле.