SCReturnInt(retval);
}
+/**
+ * Performs parsing of the content-range value
+ *
+ * @param[in] rawvalue
+ * @param[out] range
+ *
+ * @return HTP_OK on success, HTP_ERROR on failure.
+ */
+int HTPParseContentRange(bstr * rawvalue, HtpContentRange *range)
+{
+ unsigned char *data = bstr_ptr(rawvalue);
+ size_t len = bstr_len(rawvalue);
+ size_t pos = 0;
+ size_t last_pos;
+
+ // skip spaces and units
+ while (pos < len && data[pos] == ' ')
+ pos++;
+ while (pos < len && data[pos] != ' ')
+ pos++;
+ while (pos < len && data[pos] == ' ')
+ pos++;
+
+ // initialize to unseen
+ range->start = -1;
+ range->end = -1;
+ range->size = -1;
+
+ if (pos == len) {
+ // missing data
+ return -1;
+ }
+
+ if (data[pos] == '*') {
+ // case with size only
+ if (len < pos + 1 || data[pos+1] != '/') {
+ range->size = -1;
+ return -1;
+ }
+ pos += 2;
+ range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+ } else {
+ // case with start and end
+ range->start = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+ pos += last_pos;
+ if (len < pos || data[pos] != '-') {
+ return -1;
+ }
+ pos++;
+ range->end = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+ pos += last_pos;
+ if (len < pos || data[pos] != '/') {
+ return -1;
+ }
+ pos++;
+ if (data[pos] != '*') {
+ // case with size
+ range->size = bstr_util_mem_to_pint(data + pos, len - pos, 10, &last_pos);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * \brief Sets range for a file
+ *
+ * \param s http state
+ * \param rawvalue raw header value
+ *
+ * \retval 0 ok
+ * \retval -1 error
+ * \retval -2 error parsing
+ * \retval -3 error negative end in range
+ */
+int HTPFileSetRange(HtpState *s, bstr *rawvalue)
+{
+ SCEnter();
+
+ if (s == NULL) {
+ SCReturnInt(-1);
+ }
+
+ FileContainer * files = s->files_tc;
+ if (files == NULL) {
+ SCLogDebug("no files in state");
+ SCReturnInt(-1);
+ }
+
+ HtpContentRange crparsed;
+ if (HTPParseContentRange(rawvalue, &crparsed) != 0) {
+ SCLogDebug("parsing range failed");
+ SCReturnInt(-2);
+ }
+ if (crparsed.end <= 0) {
+ SCLogDebug("negative end in range");
+ SCReturnInt(-3);
+ }
+ int retval = FileSetRange(files, crparsed.start, crparsed.end);
+ if (retval == -1) {
+ SCLogDebug("set range failed");
+ }
+ SCReturnInt(retval);
+}
+
/**
* \brief Store a chunk of data in the flow
*
#ifndef __APP_LAYER_HTP_FILE_H__
#define __APP_LAYER_HTP_FILE_H__
+typedef struct HtpContentRange_ {
+ int64_t start;
+ int64_t end;
+ int64_t size;
+} HtpContentRange;
+
int HTPFileOpen(HtpState *, const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint64_t, uint8_t);
+int HTPParseContentRange(bstr * rawvalue, HtpContentRange *range);
+int HTPFileSetRange(HtpState *, bstr *rawvalue);
int HTPFileStoreChunk(HtpState *, const uint8_t *, uint32_t, uint8_t);
int HTPFileClose(HtpState *, const uint8_t *, uint32_t, uint8_t, uint8_t);
htud->tcflags |= HTP_FILENAME_SET;
htud->tcflags &= ~HTP_DONTSTORE;
}
+ //set range if present
+ htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range");
+ if (h_content_range != NULL) {
+ HTPFileSetRange(hstate, h_content_range->value);
+ }
}
}
else
json_object_set_new(fjs, "file_id", json_integer(ff->file_store_id));
}
json_object_set_new(fjs, "size", json_integer(FileTrackedSize(ff)));
+ if (ff->end > 0) {
+ json_object_set_new(fjs, "start", json_integer(ff->start));
+ json_object_set_new(fjs, "end", json_integer(ff->end));
+ }
json_object_set_new(fjs, "tx_id", json_integer(ff->txid));
/* xff header */
#include "output.h"
#include "app-layer-htp.h"
+#include "app-layer-htp-file.h"
#include "app-layer-htp-xff.h"
#include "app-layer.h"
#include "app-layer-parser.h"
*p = '\0';
json_object_set_new(js, "http_content_type", SCJsonString(string));
}
+ htp_header_t *h_content_range = htp_table_get_c(tx->response_headers, "content-range");
+ if (h_content_range != NULL) {
+ const size_t size = bstr_len(h_content_range->value) * 2 + 1;
+ char string[size];
+ BytesToStringBuffer(bstr_ptr(h_content_range->value), bstr_len(h_content_range->value), string, size);
+ json_t *crjs = json_object();
+ if (crjs != NULL) {
+ json_object_set_new(crjs, "raw", SCJsonString(string));
+ HtpContentRange crparsed;
+ if (HTPParseContentRange(h_content_range->value, &crparsed) == 0) {
+ if (crparsed.start >= 0)
+ json_object_set_new(crjs, "start", json_integer(crparsed.start));
+ if (crparsed.end >= 0)
+ json_object_set_new(crjs, "end", json_integer(crparsed.end));
+ if (crparsed.size >= 0)
+ json_object_set_new(crjs, "size", json_integer(crparsed.size));
+ }
+ json_object_set_new(js, "content_range", crjs);
+ }
+ }
}
}
SCReturnInt(-1);
}
+/**
+ * \brief Sets the offset range for a file.
+ *
+ * \param ffc the container
+ * \param start start offset
+ * \param end end offset
+ *
+ * \retval 0 ok
+ * \retval -1 error
+ */
+int FileSetRange(FileContainer *ffc, uint64_t start, uint64_t end)
+{
+ SCEnter();
+
+ if (ffc == NULL || ffc->tail == NULL) {
+ SCReturnInt(-1);
+ }
+ ffc->tail->start = start;
+ ffc->tail->end = end;
+ SCReturnInt(0);
+}
+
/**
* \brief Open a new File
*
* flag is set */
uint64_t content_stored;
uint64_t size;
+ uint64_t start;
+ uint64_t end;
uint32_t *sid; /* signature id of a rule that triggered the filestore event */
uint32_t sid_cnt;
int FileAppendGAPById(FileContainer *ffc, uint32_t track_id,
const uint8_t *data, uint32_t data_len);
+/**
+ * \brief Sets the offset range for a file.
+ *
+ * \param ffc the container
+ * \param start start offset
+ * \param end end offset
+ *
+ * \retval 0 ok
+ * \retval -1 error
+ */
+int FileSetRange(FileContainer *, uint64_t start, uint64_t end);
+
/**
* \brief Tag a file for storing
*