From ad663e0a92374936106632f1a891b2787bb1c343 Mon Sep 17 00:00:00 2001 From: Alex Apostolescu Date: Sat, 28 Dec 2024 20:55:56 +0200 Subject: [PATCH] infra/linters: Replace spellcheck with typos Use typos to find misspelled words since it does not require extensive wordlists and it is easier to configurate. The trade-off is that it will not complain about uncommon typos since it will assume they are technical terms. Overall it should be a lot easier to maintain than spellcheck. Signed-off-by: Alex Apostolescu --- .checkpatch.ignore | 3 + .github/.typos.toml | 19 + .github/workflows/actions.yml | 10 +- .vscode/settings.json | 3 + Makefile | 13 + .../support/c/sum_array_sequential.c | 2 +- .../drills/tasks/libult/solution/queue.h | 2 +- .../drills/tasks/libult/support/queue.h | 2 +- .../scheduling/guides/libult/solution/queue.h | 2 +- .../scheduling/guides/libult/support/queue.h | 2 +- .../solution/d/race_condition_atomic.d | 2 +- .../threadsafe-data-struct/support/clist.h | 220 +- .../threadsafe-data-struct/support/test.c | 2 +- .../slides/mutual-exclusion.md | 2 +- .../solution/seg-fault/sum_array_processes.d | 6 +- .../support/c/sum_array_sequential.c | 2 +- .../support/c/sum_array_sequential.c | 2 +- .../drills/tasks/access-counter/README.md | 18 +- .../solution/src/access_counter.c | 2 +- .../tasks/access-counter/support/tests/test.c | 36 +- config.yaml | 4 +- .../src/http-parser/README.md | 2 +- .../src/http-parser/http_parser.c | 2902 ++++++++--------- .../src/http-parser/http_parser.h | 2 +- .../lambda-function-loader/tests/checker.sh | 2 +- .../lambda-function-loader/tests/special.c | 2 +- .../minishell/tests/_test/run_test.sh | 2 +- .../minishell/util/parser/parser.h | 4 +- .../minishell/util/parser/parser.l | 2 +- .../minishell/util/parser/parser.y | 2 +- .../parallel-firewall/src/ring_buffer.h | 2 +- .../parallel-firewall/tests/checker.py | 6 +- gen-view.py | 12 +- 33 files changed, 1665 insertions(+), 1629 deletions(-) create mode 100644 .checkpatch.ignore create mode 100644 .github/.typos.toml create mode 100644 .vscode/settings.json diff --git a/.checkpatch.ignore b/.checkpatch.ignore new file mode 100644 index 0000000000..541c6ba0cb --- /dev/null +++ b/.checkpatch.ignore @@ -0,0 +1,3 @@ +# Ignore directories containing third-party files +chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support +content/assignments/async-web-server/src/http-parser diff --git a/.github/.typos.toml b/.github/.typos.toml new file mode 100644 index 0000000000..0678752bbc --- /dev/null +++ b/.github/.typos.toml @@ -0,0 +1,19 @@ +[default] +# ```(console)?[\\s\\S]+?``` -> Ignore fenced sequences +# -\\w+|--\\w+ -> Ignore command flags +extend-ignore-re = ["```(console)?[\\s\\S]+?```", "-\\w+|--\\w+"] +[files] +extend-exclude = [ + "*.svg", + "*.drawio", + "ssh_key", + "ssh_key.pub", + "content/assignments/async-web-server/src/http-parser/samples/Makefile", # Windows compile flags + # Third-party files + "chapters/compute/processes-threads-apache2/guides/apache2/support/httpd.conf", + "chapters/compute/processes-threads-apache2/drills/tasks/apache2/support/httpd.conf" +] +[default.extend-words] +# word1 = "word2" to correct word1 to word2 +# word3 = "word3" to consider word3 a valid word +VAS = "VAS" diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 9e25a1f3d7..0c85ceab58 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -24,11 +24,9 @@ jobs: with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - spellcheck: - name: Spellcheck + typos: + name: Typos runs-on: ubuntu-latest steps: - - name: Spellcheck - uses: open-education-hub/actions/spellcheck@main - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Typos + uses: open-education-hub/actions/typos@main diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..97924983a3 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": false +} \ No newline at end of file diff --git a/Makefile b/Makefile index f9ae686d4c..682fea2d77 100644 --- a/Makefile +++ b/Makefile @@ -39,3 +39,16 @@ clean: stop_bash cleanall: clean -docker inspect --type=image $(IMAGE_NAME) > /dev/null 2>&1 && docker image rm $(IMAGE_NAME) + +# Linters +.PHONY: lint typos +lint: typos + +typos: + @echo "Running crate-ci/typos" + @# Replace ghcr.io/alex-devis/typos:1.28.4 with ghcr.io/crate-ci/typos:latest + @# once https://github.com/crate-ci/typos/pull/1183 or equivalent is merged. + @docker run --rm -v $(PWD):/data -w /data \ + ghcr.io/alex-devis/typos:latest \ + --config .github/.typos.toml . \ + --exclude spellcheck # Do not validate spellcheck wordlist diff --git a/chapters/compute/processes/guides/sum-array-processes/support/c/sum_array_sequential.c b/chapters/compute/processes/guides/sum-array-processes/support/c/sum_array_sequential.c index f65bb20ece..95bba0605b 100644 --- a/chapters/compute/processes/guides/sum-array-processes/support/c/sum_array_sequential.c +++ b/chapters/compute/processes/guides/sum-array-processes/support/c/sum_array_sequential.c @@ -31,7 +31,7 @@ int main(void) time = 1000 * (stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec) / 1000; - printf("Array sum is %ld\nTime spent: %lu miliseconds\n", result, time); + printf("Array sum is %ld\nTime spent: %lu milliseconds\n", result, time); free(array); diff --git a/chapters/compute/scheduling/drills/tasks/libult/solution/queue.h b/chapters/compute/scheduling/drills/tasks/libult/solution/queue.h index 022d990829..a82022290b 100644 --- a/chapters/compute/scheduling/drills/tasks/libult/solution/queue.h +++ b/chapters/compute/scheduling/drills/tasks/libult/solution/queue.h @@ -58,7 +58,7 @@ void queue_destroy(QUEUE *queue); size_t queue_size(const QUEUE *queue); -/* Add elem to the end of queue. Returns 0 on succes and non-zero on +/* Add elem to the end of queue. Returns 0 on success and non-zero on * failure. */ int queue_enqueue(QUEUE *queue, TCB *elem); diff --git a/chapters/compute/scheduling/drills/tasks/libult/support/queue.h b/chapters/compute/scheduling/drills/tasks/libult/support/queue.h index 022d990829..a82022290b 100644 --- a/chapters/compute/scheduling/drills/tasks/libult/support/queue.h +++ b/chapters/compute/scheduling/drills/tasks/libult/support/queue.h @@ -58,7 +58,7 @@ void queue_destroy(QUEUE *queue); size_t queue_size(const QUEUE *queue); -/* Add elem to the end of queue. Returns 0 on succes and non-zero on +/* Add elem to the end of queue. Returns 0 on success and non-zero on * failure. */ int queue_enqueue(QUEUE *queue, TCB *elem); diff --git a/chapters/compute/scheduling/guides/libult/solution/queue.h b/chapters/compute/scheduling/guides/libult/solution/queue.h index 022d990829..a82022290b 100644 --- a/chapters/compute/scheduling/guides/libult/solution/queue.h +++ b/chapters/compute/scheduling/guides/libult/solution/queue.h @@ -58,7 +58,7 @@ void queue_destroy(QUEUE *queue); size_t queue_size(const QUEUE *queue); -/* Add elem to the end of queue. Returns 0 on succes and non-zero on +/* Add elem to the end of queue. Returns 0 on success and non-zero on * failure. */ int queue_enqueue(QUEUE *queue, TCB *elem); diff --git a/chapters/compute/scheduling/guides/libult/support/queue.h b/chapters/compute/scheduling/guides/libult/support/queue.h index 022d990829..a82022290b 100644 --- a/chapters/compute/scheduling/guides/libult/support/queue.h +++ b/chapters/compute/scheduling/guides/libult/support/queue.h @@ -58,7 +58,7 @@ void queue_destroy(QUEUE *queue); size_t queue_size(const QUEUE *queue); -/* Add elem to the end of queue. Returns 0 on succes and non-zero on +/* Add elem to the end of queue. Returns 0 on success and non-zero on * failure. */ int queue_enqueue(QUEUE *queue, TCB *elem); diff --git a/chapters/compute/synchronization/drills/tasks/race-condition/solution/d/race_condition_atomic.d b/chapters/compute/synchronization/drills/tasks/race-condition/solution/d/race_condition_atomic.d index d0f6dfca74..984ea1d847 100644 --- a/chapters/compute/synchronization/drills/tasks/race-condition/solution/d/race_condition_atomic.d +++ b/chapters/compute/synchronization/drills/tasks/race-condition/solution/d/race_condition_atomic.d @@ -16,7 +16,7 @@ void incrementVar() // `atomicOp` is a template function. It can perform any simple // operation, such as `+=`, &= or `-=`, atomically. The operations is // given to the function as a template argument using the following - // construction: !"+=". The values in parantheses are the operands + // construction: !"+=". The values in parentheses are the operands // of the atomic operation. atomicOp!"+="(var, 1); } diff --git a/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/clist.h b/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/clist.h index 2eef32074d..ec69d2b4ac 100644 --- a/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/clist.h +++ b/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/clist.h @@ -1,110 +1,110 @@ -/******************************************/ -/* */ -/* Alexander Agdgomlishvili */ -/* */ -/* cdevelopment@mail.com */ -/* */ -/******************************************/ - - -/** - * BSD 2-Clause License - * - * Copyright (c) 2020, Alexander Agdgomlishvili - * cdevelopment@mail.com - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* Github link: https://github.com/AlexanderAgd/CLIST */ - -#ifndef CLIST_H -#define CLIST_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct CList -{ - void * (* add) (struct CList *l, void *o); /* Add object to the end of a list */ - void * (* insert) (struct CList *l, void *o, int n); /* Insert object at position 'n' */ - void * (* replace) (struct CList *l, void *o, int n); /* Replace object at position 'n' */ - void (* remove) (struct CList *l, int n); /* Remove object at position 'n' */ - void * (* at) (struct CList *l, int n); /* Get object at position 'n' */ - int (* realloc) (struct CList *l, int n); /* Reallocate list to 'size' items */ - int (* count) (struct CList *l); /* Get list size in items */ - void * (* firstMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); - /* Returns object with first match of string or byte compare */ - void * (* lastMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); - /* Returns object with last match of string or byte compare */ - int (* index) (struct CList *l); /* Get index of previos search match */ - int (* swap) (struct CList *l, int a, int b); /* Swap, replace two items with index a b */ - int (* allocSize) (struct CList *l); /* Get allocated size in items */ - size_t (* itemSize) (struct CList *l); /* Get item size in bytes */ - void (* print) (struct CList *l, size_t shift, int n, const char *type); /* Print list data */ - void (* clear) (struct CList *l); /* Clear list */ - void (* free) (struct CList *l); /* Destroy struct CList and all data */ - void *priv; /* NOT FOR USE, private data */ -} CList; - -CList *CList_init(size_t objSize); /* Set list object size in bytes */ - -/* void *add(struct CList *l, void *o); - Returns pointer to added object; Returns NULL if failed. - - void *insert(struct CList *l, void *o, int n); - Returns pointer to inserted object; Returns NULL if failed. - - void *replace(struct CList *l, void *o, int n); - Returns pointer to replaced object; Returns NULL if failed. - - void *at(struct CList *l, int n); - Returns pointer to object at index n; - - int realloc(struct CList *l, int n); - Return 1 when success. Returns 0 if failed. - - void *firstMatch(struct CList *l, const void *o, size_t shift, size_t size, int string); - Returns pointer to list item when first match found. Straight scanning, from 0 to list end. - Returns NULL if search failed. - - void *lastMatch(struct CList *l, const void *o, size_t shift, size_t size, int string); - Returns pointer to list item when first match found. Reverse scanning, from list end to 0. - Returns NULL if search failed. - - int index(struct CList *l); - Returns index of last search firstMatch or lastMatch. Returns -1 if search failed. - - void print(struct CList *l, size_t shift, int n, const char *type); - Prints data of "int n" list items with offset "size_t shift" and type "const char *type". - Supported types: char, short, int, long, uintptr_t, size_t, double, string. - If type is NULL just pointers data will be printed. -*/ - -#ifdef __cplusplus -} -#endif - -#endif /* CLIST_H */ +/******************************************/ +/* */ +/* Alexander Agdgomlishvili */ +/* */ +/* cdevelopment@mail.com */ +/* */ +/******************************************/ + + +/** + * BSD 2-Clause License + * + * Copyright (c) 2020, Alexander Agdgomlishvili + * cdevelopment@mail.com + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Github link: https://github.com/AlexanderAgd/CLIST */ + +#ifndef CLIST_H +#define CLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CList +{ + void * (* add) (struct CList *l, void *o); /* Add object to the end of a list */ + void * (* insert) (struct CList *l, void *o, int n); /* Insert object at position 'n' */ + void * (* replace) (struct CList *l, void *o, int n); /* Replace object at position 'n' */ + void (* remove) (struct CList *l, int n); /* Remove object at position 'n' */ + void * (* at) (struct CList *l, int n); /* Get object at position 'n' */ + int (* realloc) (struct CList *l, int n); /* Reallocate list to 'size' items */ + int (* count) (struct CList *l); /* Get list size in items */ + void * (* firstMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); + /* Returns object with first match of string or byte compare */ + void * (* lastMatch) (struct CList *l, const void *o, size_t shift, size_t size, int string); + /* Returns object with last match of string or byte compare */ + int (* index) (struct CList *l); /* Get index of previous search match */ + int (* swap) (struct CList *l, int a, int b); /* Swap, replace two items with index a b */ + int (* allocSize) (struct CList *l); /* Get allocated size in items */ + size_t (* itemSize) (struct CList *l); /* Get item size in bytes */ + void (* print) (struct CList *l, size_t shift, int n, const char *type); /* Print list data */ + void (* clear) (struct CList *l); /* Clear list */ + void (* free) (struct CList *l); /* Destroy struct CList and all data */ + void *priv; /* NOT FOR USE, private data */ +} CList; + +CList *CList_init(size_t objSize); /* Set list object size in bytes */ + +/* void *add(struct CList *l, void *o); + Returns pointer to added object; Returns NULL if failed. + + void *insert(struct CList *l, void *o, int n); + Returns pointer to inserted object; Returns NULL if failed. + + void *replace(struct CList *l, void *o, int n); + Returns pointer to replaced object; Returns NULL if failed. + + void *at(struct CList *l, int n); + Returns pointer to object at index n; + + int realloc(struct CList *l, int n); + Return 1 when success. Returns 0 if failed. + + void *firstMatch(struct CList *l, const void *o, size_t shift, size_t size, int string); + Returns pointer to list item when first match found. Straight scanning, from 0 to list end. + Returns NULL if search failed. + + void *lastMatch(struct CList *l, const void *o, size_t shift, size_t size, int string); + Returns pointer to list item when first match found. Reverse scanning, from list end to 0. + Returns NULL if search failed. + + int index(struct CList *l); + Returns index of last search firstMatch or lastMatch. Returns -1 if search failed. + + void print(struct CList *l, size_t shift, int n, const char *type); + Prints data of "int n" list items with offset "size_t shift" and type "const char *type". + Supported types: char, short, int, long, uintptr_t, size_t, double, string. + If type is NULL just pointers data will be printed. +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* CLIST_H */ diff --git a/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/test.c b/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/test.c index 04af11c909..53a5d62f23 100644 --- a/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/test.c +++ b/chapters/compute/synchronization/drills/tasks/threadsafe-data-struct/support/test.c @@ -242,7 +242,7 @@ int main(void) /******************************************************* POINTERS LIST */ - /* If we want create list of objects located in diffent places of memory, */ + /* If we want create list of objects located in different places of memory, */ /* let create pointers list or in our case "uintptr_t" address list */ printf("Size of 'uintptr_t' = %zu bytes\n", sizeof(uintptr_t)); diff --git a/chapters/compute/synchronization/slides/mutual-exclusion.md b/chapters/compute/synchronization/slides/mutual-exclusion.md index 3624af30e0..1e6b189bbf 100644 --- a/chapters/compute/synchronization/slides/mutual-exclusion.md +++ b/chapters/compute/synchronization/slides/mutual-exclusion.md @@ -97,7 +97,7 @@ void mutex_unlock(struct mutex *m) * Prevents overhead from busy-waiting * Threads move to WAITING state while waiting for the lock * Introduces overhead from context switch -* Releasing a mutex held by another thread is [**undefinded behaviour**](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html) +* Releasing a mutex held by another thread is [**undefined behaviour**](https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_lock.html) ---- diff --git a/chapters/compute/threads/drills/tasks/sum-array-bugs/solution/seg-fault/sum_array_processes.d b/chapters/compute/threads/drills/tasks/sum-array-bugs/solution/seg-fault/sum_array_processes.d index e406699f2e..b7651331a5 100644 --- a/chapters/compute/threads/drills/tasks/sum-array-bugs/solution/seg-fault/sum_array_processes.d +++ b/chapters/compute/threads/drills/tasks/sum-array-bugs/solution/seg-fault/sum_array_processes.d @@ -62,10 +62,10 @@ void main(string[] args) for (size_t i = 0; i < numProcesses; ++i) { - size_t elemsPerThred = cast(size_t) ceil( + size_t elemsPerThread = cast(size_t) ceil( (cast(double) ARR_LEN) / numProcesses); - size_t start = i * elemsPerThred; - size_t end = min(ARR_LEN, (i + 1) * elemsPerThred); + size_t start = i * elemsPerThread; + size_t end = min(ARR_LEN, (i + 1) * elemsPerThread); // Spawn another process with the current one as its parent. children[i] = fork(); diff --git a/chapters/compute/threads/drills/tasks/sum-array/support/c/sum_array_sequential.c b/chapters/compute/threads/drills/tasks/sum-array/support/c/sum_array_sequential.c index f65bb20ece..95bba0605b 100644 --- a/chapters/compute/threads/drills/tasks/sum-array/support/c/sum_array_sequential.c +++ b/chapters/compute/threads/drills/tasks/sum-array/support/c/sum_array_sequential.c @@ -31,7 +31,7 @@ int main(void) time = 1000 * (stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec) / 1000; - printf("Array sum is %ld\nTime spent: %lu miliseconds\n", result, time); + printf("Array sum is %ld\nTime spent: %lu milliseconds\n", result, time); free(array); diff --git a/chapters/compute/threads/guides/sum-array-threads/support/c/sum_array_sequential.c b/chapters/compute/threads/guides/sum-array-threads/support/c/sum_array_sequential.c index f65bb20ece..95bba0605b 100644 --- a/chapters/compute/threads/guides/sum-array-threads/support/c/sum_array_sequential.c +++ b/chapters/compute/threads/guides/sum-array-threads/support/c/sum_array_sequential.c @@ -31,7 +31,7 @@ int main(void) time = 1000 * (stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec) / 1000; - printf("Array sum is %ld\nTime spent: %lu miliseconds\n", result, time); + printf("Array sum is %ld\nTime spent: %lu milliseconds\n", result, time); free(array); diff --git a/chapters/data/working-with-memory/drills/tasks/access-counter/README.md b/chapters/data/working-with-memory/drills/tasks/access-counter/README.md index 846030fe1b..7c35a34b53 100644 --- a/chapters/data/working-with-memory/drills/tasks/access-counter/README.md +++ b/chapters/data/working-with-memory/drills/tasks/access-counter/README.md @@ -29,15 +29,15 @@ In case of a correct solution, you will get an output such as: ```text ./run_all_tests.sh -test_acess_read ........................ passed ... 9 -test_acess_write ........................ passed ... 9 -test_acess_exec ........................ passed ... 10 -test_acess_read_write ........................ passed ... 12 -test_acess_read_exec ........................ passed ... 12 -test_acess_write_exec ........................ passed ... 12 -test_acess_exec_read ........................ passed ... 12 -test_acess_exec_write ........................ passed ... 12 -test_acess_write_read ........................ passed ... 12 +test_access_read ........................ passed ... 9 +test_access_write ........................ passed ... 9 +test_access_exec ........................ passed ... 10 +test_access_read_write ........................ passed ... 12 +test_access_read_exec ........................ passed ... 12 +test_access_write_exec ........................ passed ... 12 +test_access_exec_read ........................ passed ... 12 +test_access_exec_write ........................ passed ... 12 +test_access_write_read ........................ passed ... 12 Total: 100/100 ``` diff --git a/chapters/data/working-with-memory/drills/tasks/access-counter/solution/src/access_counter.c b/chapters/data/working-with-memory/drills/tasks/access-counter/solution/src/access_counter.c index 26cbd9954d..c953261809 100644 --- a/chapters/data/working-with-memory/drills/tasks/access-counter/solution/src/access_counter.c +++ b/chapters/data/working-with-memory/drills/tasks/access-counter/solution/src/access_counter.c @@ -45,7 +45,7 @@ static void access_handler(int signum, siginfo_t *si, void *arg) return; } - /* TODO 2: Obtain page strart address in start variable. */ + /* TODO 2: Obtain page start address in start variable. */ start = (void *) ((unsigned long) si->si_addr & ~0xFFFUL); log_debug("start: %p", start); diff --git a/chapters/data/working-with-memory/drills/tasks/access-counter/support/tests/test.c b/chapters/data/working-with-memory/drills/tasks/access-counter/support/tests/test.c index ada3c926ad..b75a1a590e 100644 --- a/chapters/data/working-with-memory/drills/tasks/access-counter/support/tests/test.c +++ b/chapters/data/working-with-memory/drills/tasks/access-counter/support/tests/test.c @@ -29,7 +29,7 @@ static void do_exec(void *addr) ((void (*)(void)) addr)(); } -static int test_acess_read(void) +static int test_access_read(void) { void *addr; @@ -42,7 +42,7 @@ static int test_acess_read(void) return counter == 1; } -static int test_acess_write(void) +static int test_access_write(void) { void *addr; @@ -55,7 +55,7 @@ static int test_acess_write(void) return counter == 2; } -static int test_acess_exec(void) +static int test_access_exec(void) { void *addr; @@ -68,7 +68,7 @@ static int test_acess_exec(void) return counter == 3; } -static int test_acess_read_write(void) +static int test_access_read_write(void) { void *addr; @@ -82,7 +82,7 @@ static int test_acess_read_write(void) return counter == 1; } -static int test_acess_read_exec(void) +static int test_access_read_exec(void) { void *addr; @@ -96,7 +96,7 @@ static int test_acess_read_exec(void) return counter == 2; } -static int test_acess_write_exec(void) +static int test_access_write_exec(void) { void *addr; @@ -110,7 +110,7 @@ static int test_acess_write_exec(void) return counter == 1; } -static int test_acess_exec_read(void) +static int test_access_exec_read(void) { void *addr; @@ -124,7 +124,7 @@ static int test_acess_exec_read(void) return counter == 0; } -static int test_acess_exec_write(void) +static int test_access_exec_write(void) { void *addr; @@ -138,7 +138,7 @@ static int test_acess_exec_write(void) return counter == 0; } -static int test_acess_write_read(void) +static int test_access_write_read(void) { void *addr; @@ -153,15 +153,15 @@ static int test_acess_write_read(void) } static struct graded_test all_tests[] = { - { test_acess_read, "test_acess_read", 9 }, - { test_acess_write, "test_acess_write", 9 }, - { test_acess_exec, "test_acess_exec", 10 }, - { test_acess_read_write, "test_acess_read_write", 12 }, - { test_acess_read_exec, "test_acess_read_exec", 12 }, - { test_acess_write_exec, "test_acess_write_exec", 12 }, - { test_acess_exec_read, "test_acess_exec_read", 12 }, - { test_acess_exec_write, "test_acess_exec_write", 12 }, - { test_acess_write_read, "test_acess_write_read", 12 } + { test_access_read, "test_access_read", 9 }, + { test_access_write, "test_access_write", 9 }, + { test_access_exec, "test_access_exec", 10 }, + { test_access_read_write, "test_access_read_write", 12 }, + { test_access_read_exec, "test_access_read_exec", 12 }, + { test_access_write_exec, "test_access_write_exec", 12 }, + { test_access_exec_read, "test_access_exec_read", 12 }, + { test_access_exec_write, "test_access_exec_write", 12 }, + { test_access_write_read, "test_access_write_read", 12 } }; int main(void) diff --git a/config.yaml b/config.yaml index 1d9cb04481..629f55b633 100644 --- a/config.yaml +++ b/config.yaml @@ -102,7 +102,7 @@ lab_structure: - reading/copy-on-write.md - guides/apache2.md - guides/fork-faults.md - - title: Lab 8 - Syncronization + - title: Lab 8 - Synchronization filename: lab8.md content: - tasks/race-condition.md @@ -313,7 +313,7 @@ docusaurus: - Not Race Condition: not-race-condition.md - Lab 6 - Multiprocess and Multithread: lab6.md - Lab 7 - Copy-on-Write: lab7.md - - Lab 8 - Syncronization: lab8.md + - Lab 8 - Synchronization: lab8.md - IO: path: /build/prepare_view/.view extra: diff --git a/content/assignments/async-web-server/src/http-parser/README.md b/content/assignments/async-web-server/src/http-parser/README.md index 72332fb35b..57b3831c19 100644 --- a/content/assignments/async-web-server/src/http-parser/README.md +++ b/content/assignments/async-web-server/src/http-parser/README.md @@ -57,7 +57,7 @@ When data is received on the socket execute the parser and check for errors. } /* Start up / continue the parser. - * Note we pass recved==0 to signal that EOF has been recieved. + * Note we pass recved==0 to signal that EOF has been received. */ nparsed = http_parser_execute(parser, &settings, buf, recved); diff --git a/content/assignments/async-web-server/src/http-parser/http_parser.c b/content/assignments/async-web-server/src/http-parser/http_parser.c index 645357a0ec..d61b4dc6a5 100644 --- a/content/assignments/async-web-server/src/http-parser/http_parser.c +++ b/content/assignments/async-web-server/src/http-parser/http_parser.c @@ -30,36 +30,36 @@ #define CALLBACK2(FOR) \ do { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser)) return (p - data); \ - } \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser)) return (p - data); \ + } \ } while (0) #define MARK(FOR) \ do { \ - FOR##_mark = p; \ + FOR##_mark = p; \ } while (0) #define CALLBACK_NOCLEAR(FOR) \ do { \ - if (FOR##_mark) { \ - if (settings->on_##FOR) { \ - if (0 != settings->on_##FOR(parser, \ - FOR##_mark, \ - p - FOR##_mark)) \ - { \ - return (p - data); \ - } \ - } \ - } \ + if (FOR##_mark) { \ + if (settings->on_##FOR) { \ + if (0 != settings->on_##FOR(parser, \ + FOR##_mark, \ + p - FOR##_mark)) \ + { \ + return (p - data); \ + } \ + } \ + } \ } while (0) #define CALLBACK(FOR) \ do { \ - CALLBACK_NOCLEAR(FOR); \ - FOR##_mark = NULL; \ + CALLBACK_NOCLEAR(FOR); \ + FOR##_mark = NULL; \ } while (0) @@ -74,30 +74,30 @@ do { \ static const char *method_strings[] = - { "DELETE" - , "GET" - , "HEAD" - , "POST" - , "PUT" - , "CONNECT" - , "OPTIONS" - , "TRACE" - , "COPY" - , "LOCK" - , "MKCOL" - , "MOVE" - , "PROPFIND" - , "PROPPATCH" - , "UNLOCK" - , "REPORT" - , "MKACTIVITY" - , "CHECKOUT" - , "MERGE" - , "M-SEARCH" - , "NOTIFY" - , "SUBSCRIBE" - , "UNSUBSCRIBE" - }; + { "DELETE" + , "GET" + , "HEAD" + , "POST" + , "PUT" + , "CONNECT" + , "OPTIONS" + , "TRACE" + , "COPY" + , "LOCK" + , "MKCOL" + , "MOVE" + , "PROPFIND" + , "PROPPATCH" + , "UNLOCK" + , "REPORT" + , "MKACTIVITY" + , "CHECKOUT" + , "MERGE" + , "M-SEARCH" + , "NOTIFY" + , "SUBSCRIBE" + , "UNSUBSCRIBE" + }; /* Tokens as defined by rfc 2616. Also lowercases them. @@ -109,195 +109,195 @@ static const char *method_strings[] = */ static const char tokens[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&', '\'', /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 0, 0, '*', '+', 0, '-', '.', '/', + 0, 0, '*', '+', 0, '-', '.', '/', /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - '0', '1', '2', '3', '4', '5', '6', '7', + '0', '1', '2', '3', '4', '5', '6', '7', /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - '8', '9', 0, 0, 0, 0, 0, 0, + '8', '9', 0, 0, 0, 0, 0, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 'x', 'y', 'z', 0, 0, 0, '^', '_', + 'x', 'y', 'z', 0, 0, 0, '^', '_', /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 'x', 'y', 'z', 0, '|', '}', '~', 0 }; + 'x', 'y', 'z', 0, '|', '}', '~', 0 }; static const int8_t unhex[256] = - {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 - ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 - }; + {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + , 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1 + ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 + }; static const uint8_t normal_url_char[256] = { /* 0 nul 1 soh 2 stx 3 etx 4 eot 5 enq 6 ack 7 bel */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 8 bs 9 ht 10 nl 11 vt 12 np 13 cr 14 so 15 si */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 16 dle 17 dc1 18 dc2 19 dc3 20 dc4 21 nak 22 syn 23 etb */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 24 can 25 em 26 sub 27 esc 28 fs 29 gs 30 rs 31 us */ - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, /* 32 sp 33 ! 34 " 35 # 36 $ 37 % 38 & 39 ' */ - 0, 1, 1, 0, 1, 1, 1, 1, + 0, 1, 1, 0, 1, 1, 1, 1, /* 40 ( 41 ) 42 * 43 + 44 , 45 - 46 . 47 / */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 48 0 49 1 50 2 51 3 52 4 53 5 54 6 55 7 */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 56 8 57 9 58 : 59 ; 60 < 61 = 62 > 63 ? */ - 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 1, 1, 0, /* 64 @ 65 A 66 B 67 C 68 D 69 E 70 F 71 G */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 72 H 73 I 74 J 75 K 76 L 77 M 78 N 79 O */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 80 P 81 Q 82 R 83 S 84 T 85 U 86 V 87 W */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 88 X 89 Y 90 Z 91 [ 92 \ 93 ] 94 ^ 95 _ */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 96 ` 97 a 98 b 99 c 100 d 101 e 102 f 103 g */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 104 h 105 i 106 j 107 k 108 l 109 m 110 n 111 o */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 112 p 113 q 114 r 115 s 116 t 117 u 118 v 119 w */ - 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, /* 120 x 121 y 122 z 123 { 124 | 125 } 126 ~ 127 del */ - 1, 1, 1, 1, 1, 1, 1, 0 }; + 1, 1, 1, 1, 1, 1, 1, 0 }; enum state - { s_dead = 1 /* important that this is > 0 */ - - , s_start_req_or_res - , s_res_or_resp_H - , s_start_res - , s_res_H - , s_res_HT - , s_res_HTT - , s_res_HTTP - , s_res_first_http_major - , s_res_http_major - , s_res_first_http_minor - , s_res_http_minor - , s_res_first_status_code - , s_res_status_code - , s_res_status - , s_res_line_almost_done - - , s_start_req - - , s_req_method - , s_req_spaces_before_url - , s_req_schema - , s_req_schema_slash - , s_req_schema_slash_slash - , s_req_host - , s_req_port - , s_req_path - , s_req_query_string_start - , s_req_query_string - , s_req_fragment_start - , s_req_fragment - , s_req_http_start - , s_req_http_H - , s_req_http_HT - , s_req_http_HTT - , s_req_http_HTTP - , s_req_first_http_major - , s_req_http_major - , s_req_first_http_minor - , s_req_http_minor - , s_req_line_almost_done - - , s_header_field_start - , s_header_field - , s_header_value_start - , s_header_value - - , s_header_almost_done - - , s_chunk_size_start - , s_chunk_size - , s_chunk_parameters - , s_chunk_size_almost_done - - , s_headers_almost_done - /* Important: 's_headers_almost_done' must be the last 'header' state. All - * states beyond this must be 'body' states. It is used for overflow - * checking. See the PARSING_HEADER() macro. - */ - - , s_chunk_data - , s_chunk_data_almost_done - , s_chunk_data_done - - , s_body_identity - , s_body_identity_eof - }; + { s_dead = 1 /* important that this is > 0 */ + + , s_start_req_or_res + , s_res_or_resp_H + , s_start_res + , s_res_H + , s_res_HT + , s_res_HTT + , s_res_HTTP + , s_res_first_http_major + , s_res_http_major + , s_res_first_http_minor + , s_res_http_minor + , s_res_first_status_code + , s_res_status_code + , s_res_status + , s_res_line_almost_done + + , s_start_req + + , s_req_method + , s_req_spaces_before_url + , s_req_schema + , s_req_schema_slash + , s_req_schema_slash_slash + , s_req_host + , s_req_port + , s_req_path + , s_req_query_string_start + , s_req_query_string + , s_req_fragment_start + , s_req_fragment + , s_req_http_start + , s_req_http_H + , s_req_http_HT + , s_req_http_HTT + , s_req_http_HTTP + , s_req_first_http_major + , s_req_http_major + , s_req_first_http_minor + , s_req_http_minor + , s_req_line_almost_done + + , s_header_field_start + , s_header_field + , s_header_value_start + , s_header_value + + , s_header_almost_done + + , s_chunk_size_start + , s_chunk_size + , s_chunk_parameters + , s_chunk_size_almost_done + + , s_headers_almost_done + /* Important: 's_headers_almost_done' must be the last 'header' state. All + * states beyond this must be 'body' states. It is used for overflow + * checking. See the PARSING_HEADER() macro. + */ + + , s_chunk_data + , s_chunk_data_almost_done + , s_chunk_data_done + + , s_body_identity + , s_body_identity_eof + }; #define PARSING_HEADER(state) (state <= s_headers_almost_done) enum header_states - { h_general = 0 - , h_C - , h_CO - , h_CON + { h_general = 0 + , h_C + , h_CO + , h_CON - , h_matching_connection - , h_matching_proxy_connection - , h_matching_content_length - , h_matching_transfer_encoding - , h_matching_upgrade + , h_matching_connection + , h_matching_proxy_connection + , h_matching_content_length + , h_matching_transfer_encoding + , h_matching_upgrade - , h_connection - , h_content_length - , h_transfer_encoding - , h_upgrade + , h_connection + , h_content_length + , h_transfer_encoding + , h_upgrade - , h_matching_transfer_encoding_chunked - , h_matching_connection_keep_alive - , h_matching_connection_close + , h_matching_transfer_encoding_chunked + , h_matching_connection_keep_alive + , h_matching_connection_close - , h_transfer_encoding_chunked - , h_connection_keep_alive - , h_connection_close - }; + , h_transfer_encoding_chunked + , h_connection_keep_alive + , h_connection_close + }; enum flags - { F_CHUNKED = 1 << 0 - , F_CONNECTION_KEEP_ALIVE = 1 << 1 - , F_CONNECTION_CLOSE = 1 << 2 - , F_TRAILING = 1 << 3 - , F_UPGRADE = 1 << 4 - , F_SKIPBODY = 1 << 5 - }; + { F_CHUNKED = 1 << 0 + , F_CONNECTION_KEEP_ALIVE = 1 << 1 + , F_CONNECTION_CLOSE = 1 << 2 + , F_TRAILING = 1 << 3 + , F_UPGRADE = 1 << 4 + , F_SKIPBODY = 1 << 5 + }; #define CR '\r' @@ -319,1299 +319,1299 @@ enum flags size_t http_parser_execute (http_parser *parser, - const http_parser_settings *settings, - const char *data, - size_t len) + const http_parser_settings *settings, + const char *data, + size_t len) { - char c, ch; - const char *p = data, *pe; - size_t to_read; - - enum state state = (enum state) parser->state; - enum header_states header_state = (enum header_states) parser->header_state; - uint64_t index = parser->index; - uint64_t nread = parser->nread; - - if (len == 0) { - switch (state) { - case s_body_identity_eof: - CALLBACK2(message_complete); - return 0; - - case s_dead: - case s_start_req_or_res: - case s_start_res: - case s_start_req: - return 0; - - default: - return 1; // error - } - } - - /* technically we could combine all of these (except for url_mark) into one - variable, saving stack space, but it seems more clear to have them - separated. */ - const char *header_field_mark = 0; - const char *header_value_mark = 0; - const char *fragment_mark = 0; - const char *query_string_mark = 0; - const char *path_mark = 0; - const char *url_mark = 0; - - if (state == s_header_field) - header_field_mark = data; - if (state == s_header_value) - header_value_mark = data; - if (state == s_req_fragment) - fragment_mark = data; - if (state == s_req_query_string) - query_string_mark = data; - if (state == s_req_path) - path_mark = data; - if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash - || state == s_req_schema_slash_slash || state == s_req_port - || state == s_req_query_string_start || state == s_req_query_string - || state == s_req_host - || state == s_req_fragment_start || state == s_req_fragment) - url_mark = data; - - for (p=data, pe=data+len; p != pe; p++) { - ch = *p; - - if (PARSING_HEADER(state)) { - ++nread; - /* Buffer overflow attack */ - if (nread > HTTP_MAX_HEADER_SIZE) goto error; - } - - switch (state) { - - case s_dead: - /* this state is used after a 'Connection: close' message - * the parser will error out if it reads another message - */ - goto error; - - case s_start_req_or_res: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = -1; - - CALLBACK2(message_begin); - - if (ch == 'H') - state = s_res_or_resp_H; - else { - parser->type = HTTP_REQUEST; - goto start_req_method_assign; - } - break; - } - - case s_res_or_resp_H: - if (ch == 'T') { - parser->type = HTTP_RESPONSE; - state = s_res_HT; - } else { - if (ch != 'E') goto error; - parser->type = HTTP_REQUEST; - parser->method = HTTP_HEAD; - index = 2; - state = s_req_method; - } - break; - - case s_start_res: - { - parser->flags = 0; - parser->content_length = -1; - - CALLBACK2(message_begin); - - switch (ch) { - case 'H': - state = s_res_H; - break; - - case CR: - case LF: - break; - - default: - goto error; - } - break; - } - - case s_res_H: - STRICT_CHECK(ch != 'T'); - state = s_res_HT; - break; - - case s_res_HT: - STRICT_CHECK(ch != 'T'); - state = s_res_HTT; - break; - - case s_res_HTT: - STRICT_CHECK(ch != 'P'); - state = s_res_HTTP; - break; - - case s_res_HTTP: - STRICT_CHECK(ch != '/'); - state = s_res_first_http_major; - break; - - case s_res_first_http_major: - if (ch < '1' || ch > '9') goto error; - parser->http_major = ch - '0'; - state = s_res_http_major; - break; - - /* major HTTP version or dot */ - case s_res_http_major: - { - if (ch == '.') { - state = s_res_first_http_minor; - break; - } - - if (ch < '0' || ch > '9') goto error; - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) goto error; - break; - } - - /* first digit of minor HTTP version */ - case s_res_first_http_minor: - if (ch < '0' || ch > '9') goto error; - parser->http_minor = ch - '0'; - state = s_res_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_res_http_minor: - { - if (ch == ' ') { - state = s_res_first_status_code; - break; - } - - if (ch < '0' || ch > '9') goto error; - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) goto error; - break; - } - - case s_res_first_status_code: - { - if (ch < '0' || ch > '9') { - if (ch == ' ') { - break; - } - goto error; - } - parser->status_code = ch - '0'; - state = s_res_status_code; - break; - } - - case s_res_status_code: - { - if (ch < '0' || ch > '9') { - switch (ch) { - case ' ': - state = s_res_status; - break; - case CR: - state = s_res_line_almost_done; - break; - case LF: - state = s_header_field_start; - break; - default: - goto error; - } - break; - } - - parser->status_code *= 10; - parser->status_code += ch - '0'; - - if (parser->status_code > 999) goto error; - break; - } - - case s_res_status: - /* the human readable status. e.g. "NOT FOUND" - * we are not humans so just ignore this */ - if (ch == CR) { - state = s_res_line_almost_done; - break; - } - - if (ch == LF) { - state = s_header_field_start; - break; - } - break; - - case s_res_line_almost_done: - STRICT_CHECK(ch != LF); - state = s_header_field_start; - break; - - case s_start_req: - { - if (ch == CR || ch == LF) - break; - parser->flags = 0; - parser->content_length = -1; - - CALLBACK2(message_begin); - - if (ch < 'A' || 'Z' < ch) goto error; - - start_req_method_assign: - parser->method = (enum http_method) 0; - index = 1; - switch (ch) { - case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; - case 'D': parser->method = HTTP_DELETE; break; - case 'G': parser->method = HTTP_GET; break; - case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; - case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; - case 'N': parser->method = HTTP_NOTIFY; break; - case 'O': parser->method = HTTP_OPTIONS; break; - case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break; - case 'R': parser->method = HTTP_REPORT; break; - case 'S': parser->method = HTTP_SUBSCRIBE; break; - case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; - default: goto error; - } - state = s_req_method; - break; - } - - case s_req_method: - { - if (ch == '\0') - goto error; - - const char *matcher = method_strings[parser->method]; - if (ch == ' ' && matcher[index] == '\0') { - state = s_req_spaces_before_url; - } else if (ch == matcher[index]) { - ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } - } else if (parser->method == HTTP_MKCOL) { - if (index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } - } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') { - parser->method = HTTP_PUT; - } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') { - parser->method = HTTP_UNSUBSCRIBE; - } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; - } else { - goto error; - } - - ++index; - break; - } - case s_req_spaces_before_url: - { - if (ch == ' ') break; - - if (ch == '/' || ch == '*') { - MARK(url); - MARK(path); - state = s_req_path; - break; - } - - c = LOWER(ch); - - if (c >= 'a' && c <= 'z') { - MARK(url); - state = s_req_schema; - break; - } - - goto error; - } - - case s_req_schema: - { - c = LOWER(ch); - - if (c >= 'a' && c <= 'z') break; - - if (ch == ':') { - state = s_req_schema_slash; - break; - } else if (ch == '.') { - state = s_req_host; - break; - } else if ('0' <= ch && ch <= '9') { - state = s_req_host; - break; - } - - goto error; - } - - case s_req_schema_slash: - STRICT_CHECK(ch != '/'); - state = s_req_schema_slash_slash; - break; - - case s_req_schema_slash_slash: - STRICT_CHECK(ch != '/'); - state = s_req_host; - break; - - case s_req_host: - { - c = LOWER(ch); - if (c >= 'a' && c <= 'z') break; - if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break; - switch (ch) { - case ':': - state = s_req_port; - break; - case '/': - MARK(path); - state = s_req_path; - break; - case ' ': - /* The request line looks like: - * "GET http://foo.bar.com HTTP/1.1" - * That is, there is no path. - */ - CALLBACK(url); - state = s_req_http_start; - break; - default: - goto error; - } - break; - } - - case s_req_port: - { - if (ch >= '0' && ch <= '9') break; - switch (ch) { - case '/': - MARK(path); - state = s_req_path; - break; - case ' ': - /* The request line looks like: - * "GET http://foo.bar.com:1234 HTTP/1.1" - * That is, there is no path. - */ - CALLBACK(url); - state = s_req_http_start; - break; - default: - goto error; - } - break; - } - - case s_req_path: - { - if (normal_url_char[(unsigned char)ch]) break; - - switch (ch) { - case ' ': - CALLBACK(url); - CALLBACK(path); - state = s_req_http_start; - break; - case CR: - CALLBACK(url); - CALLBACK(path); - parser->http_major = 0; - parser->http_minor = 9; - state = s_req_line_almost_done; - break; - case LF: - CALLBACK(url); - CALLBACK(path); - parser->http_major = 0; - parser->http_minor = 9; - state = s_header_field_start; - break; - case '?': - CALLBACK(path); - state = s_req_query_string_start; - break; - case '#': - CALLBACK(path); - state = s_req_fragment_start; - break; - default: - goto error; - } - break; - } - - case s_req_query_string_start: - { - if (normal_url_char[(unsigned char)ch]) { - MARK(query_string); - state = s_req_query_string; - break; - } - - switch (ch) { - case '?': - break; /* XXX ignore extra '?' ... is this right? */ - case ' ': - CALLBACK(url); - state = s_req_http_start; - break; - case CR: - CALLBACK(url); - parser->http_major = 0; - parser->http_minor = 9; - state = s_req_line_almost_done; - break; - case LF: - CALLBACK(url); - parser->http_major = 0; - parser->http_minor = 9; - state = s_header_field_start; - break; - case '#': - state = s_req_fragment_start; - break; - default: - goto error; - } - break; - } - - case s_req_query_string: - { - if (normal_url_char[(unsigned char)ch]) break; - - switch (ch) { - case '?': - /* allow extra '?' in query string */ - break; - case ' ': - CALLBACK(url); - CALLBACK(query_string); - state = s_req_http_start; - break; - case CR: - CALLBACK(url); - CALLBACK(query_string); - parser->http_major = 0; - parser->http_minor = 9; - state = s_req_line_almost_done; - break; - case LF: - CALLBACK(url); - CALLBACK(query_string); - parser->http_major = 0; - parser->http_minor = 9; - state = s_header_field_start; - break; - case '#': - CALLBACK(query_string); - state = s_req_fragment_start; - break; - default: - goto error; - } - break; - } - - case s_req_fragment_start: - { - if (normal_url_char[(unsigned char)ch]) { - MARK(fragment); - state = s_req_fragment; - break; - } - - switch (ch) { - case ' ': - CALLBACK(url); - state = s_req_http_start; - break; - case CR: - CALLBACK(url); - parser->http_major = 0; - parser->http_minor = 9; - state = s_req_line_almost_done; - break; - case LF: - CALLBACK(url); - parser->http_major = 0; - parser->http_minor = 9; - state = s_header_field_start; - break; - case '?': - MARK(fragment); - state = s_req_fragment; - break; - case '#': - break; - default: - goto error; - } - break; - } - - case s_req_fragment: - { - if (normal_url_char[(unsigned char)ch]) break; - - switch (ch) { - case ' ': - CALLBACK(url); - CALLBACK(fragment); - state = s_req_http_start; - break; - case CR: - CALLBACK(url); - CALLBACK(fragment); - parser->http_major = 0; - parser->http_minor = 9; - state = s_req_line_almost_done; - break; - case LF: - CALLBACK(url); - CALLBACK(fragment); - parser->http_major = 0; - parser->http_minor = 9; - state = s_header_field_start; - break; - case '?': - case '#': - break; - default: - goto error; - } - break; - } - - case s_req_http_start: - switch (ch) { - case 'H': - state = s_req_http_H; - break; - case ' ': - break; - default: - goto error; - } - break; - - case s_req_http_H: - STRICT_CHECK(ch != 'T'); - state = s_req_http_HT; - break; - - case s_req_http_HT: - STRICT_CHECK(ch != 'T'); - state = s_req_http_HTT; - break; - - case s_req_http_HTT: - STRICT_CHECK(ch != 'P'); - state = s_req_http_HTTP; - break; - - case s_req_http_HTTP: - STRICT_CHECK(ch != '/'); - state = s_req_first_http_major; - break; - - /* first digit of major HTTP version */ - case s_req_first_http_major: - if (ch < '1' || ch > '9') goto error; - parser->http_major = ch - '0'; - state = s_req_http_major; - break; - - /* major HTTP version or dot */ - case s_req_http_major: - { - if (ch == '.') { - state = s_req_first_http_minor; - break; - } - - if (ch < '0' || ch > '9') goto error; - - parser->http_major *= 10; - parser->http_major += ch - '0'; - - if (parser->http_major > 999) goto error; - break; - } - - /* first digit of minor HTTP version */ - case s_req_first_http_minor: - if (ch < '0' || ch > '9') goto error; - parser->http_minor = ch - '0'; - state = s_req_http_minor; - break; - - /* minor HTTP version or end of request line */ - case s_req_http_minor: - { - if (ch == CR) { - state = s_req_line_almost_done; - break; - } - - if (ch == LF) { - state = s_header_field_start; - break; - } - - /* XXX allow spaces after digit? */ - - if (ch < '0' || ch > '9') goto error; - - parser->http_minor *= 10; - parser->http_minor += ch - '0'; - - if (parser->http_minor > 999) goto error; - break; - } - - /* end of request line */ - case s_req_line_almost_done: - { - if (ch != LF) goto error; - state = s_header_field_start; - break; - } - - case s_header_field_start: - { - if (ch == CR) { - state = s_headers_almost_done; - break; - } - - if (ch == LF) { - /* they might be just sending \n instead of \r\n so this would be - * the second \n to denote the end of headers*/ - state = s_headers_almost_done; - goto headers_almost_done; - } - - c = TOKEN(ch); - - if (!c) goto error; - - MARK(header_field); - - index = 0; - state = s_header_field; - - switch (c) { - case 'c': - header_state = h_C; - break; - - case 'p': - header_state = h_matching_proxy_connection; - break; - - case 't': - header_state = h_matching_transfer_encoding; - break; - - case 'u': - header_state = h_matching_upgrade; - break; - - default: - header_state = h_general; - break; - } - break; - } - - case s_header_field: - { - c = TOKEN(ch); - - if (c) { - switch (header_state) { - case h_general: - break; - - case h_C: - index++; - header_state = (c == 'o' ? h_CO : h_general); - break; - - case h_CO: - index++; - header_state = (c == 'n' ? h_CON : h_general); - break; - - case h_CON: - index++; - switch (c) { - case 'n': - header_state = h_matching_connection; - break; - case 't': - header_state = h_matching_content_length; - break; - default: - header_state = h_general; - break; - } - break; - - /* connection */ - - case h_matching_connection: - index++; - if (index > sizeof(CONNECTION)-1 - || c != CONNECTION[index]) { - header_state = h_general; - } else if (index == sizeof(CONNECTION)-2) { - header_state = h_connection; - } - break; - - /* proxy-connection */ - - case h_matching_proxy_connection: - index++; - if (index > sizeof(PROXY_CONNECTION)-1 - || c != PROXY_CONNECTION[index]) { - header_state = h_general; - } else if (index == sizeof(PROXY_CONNECTION)-2) { - header_state = h_connection; - } - break; - - /* content-length */ - - case h_matching_content_length: - index++; - if (index > sizeof(CONTENT_LENGTH)-1 - || c != CONTENT_LENGTH[index]) { - header_state = h_general; - } else if (index == sizeof(CONTENT_LENGTH)-2) { - header_state = h_content_length; - } - break; - - /* transfer-encoding */ - - case h_matching_transfer_encoding: - index++; - if (index > sizeof(TRANSFER_ENCODING)-1 - || c != TRANSFER_ENCODING[index]) { - header_state = h_general; - } else if (index == sizeof(TRANSFER_ENCODING)-2) { - header_state = h_transfer_encoding; - } - break; - - /* upgrade */ - - case h_matching_upgrade: - index++; - if (index > sizeof(UPGRADE)-1 - || c != UPGRADE[index]) { - header_state = h_general; - } else if (index == sizeof(UPGRADE)-2) { - header_state = h_upgrade; - } - break; - - case h_connection: - case h_content_length: - case h_transfer_encoding: - case h_upgrade: - if (ch != ' ') header_state = h_general; - break; - - default: - assert(0 && "Unknown header_state"); - break; - } - break; - } - - if (ch == ':') { - CALLBACK(header_field); - state = s_header_value_start; - break; - } - - if (ch == CR) { - state = s_header_almost_done; - CALLBACK(header_field); - break; - } - - if (ch == LF) { - CALLBACK(header_field); - state = s_header_field_start; - break; - } - - goto error; - } - - case s_header_value_start: - { - if (ch == ' ') break; - - MARK(header_value); - - state = s_header_value; - index = 0; - - c = LOWER(ch); - - if (ch == CR) { - CALLBACK(header_value); - header_state = h_general; - state = s_header_almost_done; - break; - } - - if (ch == LF) { - CALLBACK(header_value); - state = s_header_field_start; - break; - } - - switch (header_state) { - case h_upgrade: - parser->flags |= F_UPGRADE; - header_state = h_general; - break; - - case h_transfer_encoding: - /* looking for 'Transfer-Encoding: chunked' */ - if ('c' == c) { - header_state = h_matching_transfer_encoding_chunked; - } else { - header_state = h_general; - } - break; - - case h_content_length: - if (ch < '0' || ch > '9') goto error; - parser->content_length = ch - '0'; - break; - - case h_connection: - /* looking for 'Connection: keep-alive' */ - if (c == 'k') { - header_state = h_matching_connection_keep_alive; - /* looking for 'Connection: close' */ - } else if (c == 'c') { - header_state = h_matching_connection_close; - } else { - header_state = h_general; - } - break; - - default: - header_state = h_general; - break; - } - break; - } - - case s_header_value: - { - c = LOWER(ch); - - if (ch == CR) { - CALLBACK(header_value); - state = s_header_almost_done; - break; - } - - if (ch == LF) { - CALLBACK(header_value); - goto header_almost_done; - } - - switch (header_state) { - case h_general: - break; - - case h_connection: - case h_transfer_encoding: - assert(0 && "Shouldn't get here."); - break; - - case h_content_length: - if (ch == ' ') break; - if (ch < '0' || ch > '9') goto error; - parser->content_length *= 10; - parser->content_length += ch - '0'; - break; - - /* Transfer-Encoding: chunked */ - case h_matching_transfer_encoding_chunked: - index++; - if (index > sizeof(CHUNKED)-1 - || c != CHUNKED[index]) { - header_state = h_general; - } else if (index == sizeof(CHUNKED)-2) { - header_state = h_transfer_encoding_chunked; - } - break; - - /* looking for 'Connection: keep-alive' */ - case h_matching_connection_keep_alive: - index++; - if (index > sizeof(KEEP_ALIVE)-1 - || c != KEEP_ALIVE[index]) { - header_state = h_general; - } else if (index == sizeof(KEEP_ALIVE)-2) { - header_state = h_connection_keep_alive; - } - break; - - /* looking for 'Connection: close' */ - case h_matching_connection_close: - index++; - if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) { - header_state = h_general; - } else if (index == sizeof(CLOSE)-2) { - header_state = h_connection_close; - } - break; - - case h_transfer_encoding_chunked: - case h_connection_keep_alive: - case h_connection_close: - if (ch != ' ') header_state = h_general; - break; - - default: - state = s_header_value; - header_state = h_general; - break; - } - break; - } - - case s_header_almost_done: - header_almost_done: - { - STRICT_CHECK(ch != LF); - - state = s_header_field_start; - - switch (header_state) { - case h_connection_keep_alive: - parser->flags |= F_CONNECTION_KEEP_ALIVE; - break; - case h_connection_close: - parser->flags |= F_CONNECTION_CLOSE; - break; - case h_transfer_encoding_chunked: - parser->flags |= F_CHUNKED; - break; - default: - break; - } - break; - } - - case s_headers_almost_done: - headers_almost_done: - { - STRICT_CHECK(ch != LF); - - if (parser->flags & F_TRAILING) { - /* End of a chunked request */ - CALLBACK2(message_complete); - state = NEW_MESSAGE(); - break; - } - - nread = 0; - - if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) { - parser->upgrade = 1; - } - - /* Here we call the headers_complete callback. This is somewhat - * different than other callbacks because if the user returns 1, we - * will interpret that as saying that this message has no body. This - * is needed for the annoying case of recieving a response to a HEAD - * request. - */ - if (settings->on_headers_complete) { - switch (settings->on_headers_complete(parser)) { - case 0: - break; - - case 1: - parser->flags |= F_SKIPBODY; - break; - - default: - parser->state = state; - return p - data; /* Error */ - } - } - - /* Exit, the rest of the connect is in a different protocol. */ - if (parser->upgrade) { - CALLBACK2(message_complete); - return (p - data); - } - - if (parser->flags & F_SKIPBODY) { - CALLBACK2(message_complete); - state = NEW_MESSAGE(); - } else if (parser->flags & F_CHUNKED) { - /* chunked encoding - ignore Content-Length header */ - state = s_chunk_size_start; - } else { - if (parser->content_length == 0) { - /* Content-Length header given but zero: Content-Length: 0\r\n */ - CALLBACK2(message_complete); - state = NEW_MESSAGE(); - } else if (parser->content_length > 0) { - /* Content-Length header given and non-zero */ - state = s_body_identity; - } else { - if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) { - /* Assume content-length 0 - read the next */ - CALLBACK2(message_complete); - state = NEW_MESSAGE(); - } else { - /* Read body until EOF */ - state = s_body_identity_eof; - } - } - } - - break; - } - - case s_body_identity: - to_read = MIN((size_t)(pe - p), parser->content_length); - if (to_read > 0) { - if (settings->on_body) settings->on_body(parser, p, to_read); - p += to_read - 1; - parser->content_length -= to_read; - if (parser->content_length == 0) { - CALLBACK2(message_complete); - state = NEW_MESSAGE(); - } - } - break; - - /* read until EOF */ - case s_body_identity_eof: - to_read = pe - p; - if (to_read > 0) { - if (settings->on_body) settings->on_body(parser, p, to_read); - p += to_read - 1; - } - break; - - case s_chunk_size_start: - { - assert(nread == 1); - assert(parser->flags & F_CHUNKED); - - c = unhex[(unsigned char)ch]; - if (c == -1) goto error; - parser->content_length = c; - state = s_chunk_size; - break; - } - - case s_chunk_size: - { - assert(parser->flags & F_CHUNKED); - - if (ch == CR) { - state = s_chunk_size_almost_done; - break; - } - - c = unhex[(unsigned char)ch]; - - if (c == -1) { - if (ch == ';' || ch == ' ') { - state = s_chunk_parameters; - break; - } - goto error; - } - - parser->content_length *= 16; - parser->content_length += c; - break; - } - - case s_chunk_parameters: - { - assert(parser->flags & F_CHUNKED); - /* just ignore this shit. TODO check for overflow */ - if (ch == CR) { - state = s_chunk_size_almost_done; - break; - } - break; - } - - case s_chunk_size_almost_done: - { - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - - nread = 0; - - if (parser->content_length == 0) { - parser->flags |= F_TRAILING; - state = s_header_field_start; - } else { - state = s_chunk_data; - } - break; - } - - case s_chunk_data: - { - assert(parser->flags & F_CHUNKED); - - to_read = MIN(pe - p, (int64_t)(parser->content_length)); - - if (to_read > 0) { - if (settings->on_body) settings->on_body(parser, p, to_read); - p += to_read - 1; - } - - if (to_read == parser->content_length) { - state = s_chunk_data_almost_done; - } - - parser->content_length -= to_read; - break; - } - - case s_chunk_data_almost_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != CR); - state = s_chunk_data_done; - break; - - case s_chunk_data_done: - assert(parser->flags & F_CHUNKED); - STRICT_CHECK(ch != LF); - state = s_chunk_size_start; - break; - - default: - assert(0 && "unhandled state"); - goto error; - } - } - - CALLBACK_NOCLEAR(header_field); - CALLBACK_NOCLEAR(header_value); - CALLBACK_NOCLEAR(fragment); - CALLBACK_NOCLEAR(query_string); - CALLBACK_NOCLEAR(path); - CALLBACK_NOCLEAR(url); - - parser->state = state; - parser->header_state = header_state; - parser->index = (unsigned char)index; - parser->nread = (unsigned char)nread; - - return len; + char c, ch; + const char *p = data, *pe; + size_t to_read; + + enum state state = (enum state) parser->state; + enum header_states header_state = (enum header_states) parser->header_state; + uint64_t index = parser->index; + uint64_t nread = parser->nread; + + if (len == 0) { + switch (state) { + case s_body_identity_eof: + CALLBACK2(message_complete); + return 0; + + case s_dead: + case s_start_req_or_res: + case s_start_res: + case s_start_req: + return 0; + + default: + return 1; // error + } + } + + /* technically we could combine all of these (except for url_mark) into one + variable, saving stack space, but it seems more clear to have them + separated. */ + const char *header_field_mark = 0; + const char *header_value_mark = 0; + const char *fragment_mark = 0; + const char *query_string_mark = 0; + const char *path_mark = 0; + const char *url_mark = 0; + + if (state == s_header_field) + header_field_mark = data; + if (state == s_header_value) + header_value_mark = data; + if (state == s_req_fragment) + fragment_mark = data; + if (state == s_req_query_string) + query_string_mark = data; + if (state == s_req_path) + path_mark = data; + if (state == s_req_path || state == s_req_schema || state == s_req_schema_slash + || state == s_req_schema_slash_slash || state == s_req_port + || state == s_req_query_string_start || state == s_req_query_string + || state == s_req_host + || state == s_req_fragment_start || state == s_req_fragment) + url_mark = data; + + for (p=data, pe=data+len; p != pe; p++) { + ch = *p; + + if (PARSING_HEADER(state)) { + ++nread; + /* Buffer overflow attack */ + if (nread > HTTP_MAX_HEADER_SIZE) goto error; + } + + switch (state) { + + case s_dead: + /* this state is used after a 'Connection: close' message + * the parser will error out if it reads another message + */ + goto error; + + case s_start_req_or_res: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = -1; + + CALLBACK2(message_begin); + + if (ch == 'H') + state = s_res_or_resp_H; + else { + parser->type = HTTP_REQUEST; + goto start_req_method_assign; + } + break; + } + + case s_res_or_resp_H: + if (ch == 'T') { + parser->type = HTTP_RESPONSE; + state = s_res_HT; + } else { + if (ch != 'E') goto error; + parser->type = HTTP_REQUEST; + parser->method = HTTP_HEAD; + index = 2; + state = s_req_method; + } + break; + + case s_start_res: + { + parser->flags = 0; + parser->content_length = -1; + + CALLBACK2(message_begin); + + switch (ch) { + case 'H': + state = s_res_H; + break; + + case CR: + case LF: + break; + + default: + goto error; + } + break; + } + + case s_res_H: + STRICT_CHECK(ch != 'T'); + state = s_res_HT; + break; + + case s_res_HT: + STRICT_CHECK(ch != 'T'); + state = s_res_HTT; + break; + + case s_res_HTT: + STRICT_CHECK(ch != 'P'); + state = s_res_HTTP; + break; + + case s_res_HTTP: + STRICT_CHECK(ch != '/'); + state = s_res_first_http_major; + break; + + case s_res_first_http_major: + if (ch < '1' || ch > '9') goto error; + parser->http_major = ch - '0'; + state = s_res_http_major; + break; + + /* major HTTP version or dot */ + case s_res_http_major: + { + if (ch == '.') { + state = s_res_first_http_minor; + break; + } + + if (ch < '0' || ch > '9') goto error; + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) goto error; + break; + } + + /* first digit of minor HTTP version */ + case s_res_first_http_minor: + if (ch < '0' || ch > '9') goto error; + parser->http_minor = ch - '0'; + state = s_res_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_res_http_minor: + { + if (ch == ' ') { + state = s_res_first_status_code; + break; + } + + if (ch < '0' || ch > '9') goto error; + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) goto error; + break; + } + + case s_res_first_status_code: + { + if (ch < '0' || ch > '9') { + if (ch == ' ') { + break; + } + goto error; + } + parser->status_code = ch - '0'; + state = s_res_status_code; + break; + } + + case s_res_status_code: + { + if (ch < '0' || ch > '9') { + switch (ch) { + case ' ': + state = s_res_status; + break; + case CR: + state = s_res_line_almost_done; + break; + case LF: + state = s_header_field_start; + break; + default: + goto error; + } + break; + } + + parser->status_code *= 10; + parser->status_code += ch - '0'; + + if (parser->status_code > 999) goto error; + break; + } + + case s_res_status: + /* the human readable status. e.g. "NOT FOUND" + * we are not humans so just ignore this */ + if (ch == CR) { + state = s_res_line_almost_done; + break; + } + + if (ch == LF) { + state = s_header_field_start; + break; + } + break; + + case s_res_line_almost_done: + STRICT_CHECK(ch != LF); + state = s_header_field_start; + break; + + case s_start_req: + { + if (ch == CR || ch == LF) + break; + parser->flags = 0; + parser->content_length = -1; + + CALLBACK2(message_begin); + + if (ch < 'A' || 'Z' < ch) goto error; + + start_req_method_assign: + parser->method = (enum http_method) 0; + index = 1; + switch (ch) { + case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; + case 'D': parser->method = HTTP_DELETE; break; + case 'G': parser->method = HTTP_GET; break; + case 'H': parser->method = HTTP_HEAD; break; + case 'L': parser->method = HTTP_LOCK; break; + case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH */ break; + case 'N': parser->method = HTTP_NOTIFY; break; + case 'O': parser->method = HTTP_OPTIONS; break; + case 'P': parser->method = HTTP_POST; /* or PROPFIND or PROPPATCH or PUT */ break; + case 'R': parser->method = HTTP_REPORT; break; + case 'S': parser->method = HTTP_SUBSCRIBE; break; + case 'T': parser->method = HTTP_TRACE; break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; + default: goto error; + } + state = s_req_method; + break; + } + + case s_req_method: + { + if (ch == '\0') + goto error; + + const char *matcher = method_strings[parser->method]; + if (ch == ' ' && matcher[index] == '\0') { + state = s_req_spaces_before_url; + } else if (ch == matcher[index]) { + ; /* nada */ + } else if (parser->method == HTTP_CONNECT) { + if (index == 1 && ch == 'H') { + parser->method = HTTP_CHECKOUT; + } else if (index == 2 && ch == 'P') { + parser->method = HTTP_COPY; + } + } else if (parser->method == HTTP_MKCOL) { + if (index == 1 && ch == 'O') { + parser->method = HTTP_MOVE; + } else if (index == 1 && ch == 'E') { + parser->method = HTTP_MERGE; + } else if (index == 1 && ch == '-') { + parser->method = HTTP_MSEARCH; + } else if (index == 2 && ch == 'A') { + parser->method = HTTP_MKACTIVITY; + } + } else if (index == 1 && parser->method == HTTP_POST && ch == 'R') { + parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ + } else if (index == 1 && parser->method == HTTP_POST && ch == 'U') { + parser->method = HTTP_PUT; + } else if (index == 2 && parser->method == HTTP_UNLOCK && ch == 'S') { + parser->method = HTTP_UNSUBSCRIBE; + } else if (index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { + parser->method = HTTP_PROPPATCH; + } else { + goto error; + } + + ++index; + break; + } + case s_req_spaces_before_url: + { + if (ch == ' ') break; + + if (ch == '/' || ch == '*') { + MARK(url); + MARK(path); + state = s_req_path; + break; + } + + c = LOWER(ch); + + if (c >= 'a' && c <= 'z') { + MARK(url); + state = s_req_schema; + break; + } + + goto error; + } + + case s_req_schema: + { + c = LOWER(ch); + + if (c >= 'a' && c <= 'z') break; + + if (ch == ':') { + state = s_req_schema_slash; + break; + } else if (ch == '.') { + state = s_req_host; + break; + } else if ('0' <= ch && ch <= '9') { + state = s_req_host; + break; + } + + goto error; + } + + case s_req_schema_slash: + STRICT_CHECK(ch != '/'); + state = s_req_schema_slash_slash; + break; + + case s_req_schema_slash_slash: + STRICT_CHECK(ch != '/'); + state = s_req_host; + break; + + case s_req_host: + { + c = LOWER(ch); + if (c >= 'a' && c <= 'z') break; + if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') break; + switch (ch) { + case ':': + state = s_req_port; + break; + case '/': + MARK(path); + state = s_req_path; + break; + case ' ': + /* The request line looks like: + * "GET http://foo.bar.com HTTP/1.1" + * That is, there is no path. + */ + CALLBACK(url); + state = s_req_http_start; + break; + default: + goto error; + } + break; + } + + case s_req_port: + { + if (ch >= '0' && ch <= '9') break; + switch (ch) { + case '/': + MARK(path); + state = s_req_path; + break; + case ' ': + /* The request line looks like: + * "GET http://foo.bar.com:1234 HTTP/1.1" + * That is, there is no path. + */ + CALLBACK(url); + state = s_req_http_start; + break; + default: + goto error; + } + break; + } + + case s_req_path: + { + if (normal_url_char[(unsigned char)ch]) break; + + switch (ch) { + case ' ': + CALLBACK(url); + CALLBACK(path); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(path); + parser->http_major = 0; + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(path); + parser->http_major = 0; + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + CALLBACK(path); + state = s_req_query_string_start; + break; + case '#': + CALLBACK(path); + state = s_req_fragment_start; + break; + default: + goto error; + } + break; + } + + case s_req_query_string_start: + { + if (normal_url_char[(unsigned char)ch]) { + MARK(query_string); + state = s_req_query_string; + break; + } + + switch (ch) { + case '?': + break; /* XXX ignore extra '?' ... is this right? */ + case ' ': + CALLBACK(url); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + parser->http_major = 0; + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + parser->http_major = 0; + parser->http_minor = 9; + state = s_header_field_start; + break; + case '#': + state = s_req_fragment_start; + break; + default: + goto error; + } + break; + } + + case s_req_query_string: + { + if (normal_url_char[(unsigned char)ch]) break; + + switch (ch) { + case '?': + /* allow extra '?' in query string */ + break; + case ' ': + CALLBACK(url); + CALLBACK(query_string); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(query_string); + parser->http_major = 0; + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(query_string); + parser->http_major = 0; + parser->http_minor = 9; + state = s_header_field_start; + break; + case '#': + CALLBACK(query_string); + state = s_req_fragment_start; + break; + default: + goto error; + } + break; + } + + case s_req_fragment_start: + { + if (normal_url_char[(unsigned char)ch]) { + MARK(fragment); + state = s_req_fragment; + break; + } + + switch (ch) { + case ' ': + CALLBACK(url); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + parser->http_major = 0; + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + parser->http_major = 0; + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + MARK(fragment); + state = s_req_fragment; + break; + case '#': + break; + default: + goto error; + } + break; + } + + case s_req_fragment: + { + if (normal_url_char[(unsigned char)ch]) break; + + switch (ch) { + case ' ': + CALLBACK(url); + CALLBACK(fragment); + state = s_req_http_start; + break; + case CR: + CALLBACK(url); + CALLBACK(fragment); + parser->http_major = 0; + parser->http_minor = 9; + state = s_req_line_almost_done; + break; + case LF: + CALLBACK(url); + CALLBACK(fragment); + parser->http_major = 0; + parser->http_minor = 9; + state = s_header_field_start; + break; + case '?': + case '#': + break; + default: + goto error; + } + break; + } + + case s_req_http_start: + switch (ch) { + case 'H': + state = s_req_http_H; + break; + case ' ': + break; + default: + goto error; + } + break; + + case s_req_http_H: + STRICT_CHECK(ch != 'T'); + state = s_req_http_HT; + break; + + case s_req_http_HT: + STRICT_CHECK(ch != 'T'); + state = s_req_http_HTT; + break; + + case s_req_http_HTT: + STRICT_CHECK(ch != 'P'); + state = s_req_http_HTTP; + break; + + case s_req_http_HTTP: + STRICT_CHECK(ch != '/'); + state = s_req_first_http_major; + break; + + /* first digit of major HTTP version */ + case s_req_first_http_major: + if (ch < '1' || ch > '9') goto error; + parser->http_major = ch - '0'; + state = s_req_http_major; + break; + + /* major HTTP version or dot */ + case s_req_http_major: + { + if (ch == '.') { + state = s_req_first_http_minor; + break; + } + + if (ch < '0' || ch > '9') goto error; + + parser->http_major *= 10; + parser->http_major += ch - '0'; + + if (parser->http_major > 999) goto error; + break; + } + + /* first digit of minor HTTP version */ + case s_req_first_http_minor: + if (ch < '0' || ch > '9') goto error; + parser->http_minor = ch - '0'; + state = s_req_http_minor; + break; + + /* minor HTTP version or end of request line */ + case s_req_http_minor: + { + if (ch == CR) { + state = s_req_line_almost_done; + break; + } + + if (ch == LF) { + state = s_header_field_start; + break; + } + + /* XXX allow spaces after digit? */ + + if (ch < '0' || ch > '9') goto error; + + parser->http_minor *= 10; + parser->http_minor += ch - '0'; + + if (parser->http_minor > 999) goto error; + break; + } + + /* end of request line */ + case s_req_line_almost_done: + { + if (ch != LF) goto error; + state = s_header_field_start; + break; + } + + case s_header_field_start: + { + if (ch == CR) { + state = s_headers_almost_done; + break; + } + + if (ch == LF) { + /* they might be just sending \n instead of \r\n so this would be + * the second \n to denote the end of headers*/ + state = s_headers_almost_done; + goto headers_almost_done; + } + + c = TOKEN(ch); + + if (!c) goto error; + + MARK(header_field); + + index = 0; + state = s_header_field; + + switch (c) { + case 'c': + header_state = h_C; + break; + + case 'p': + header_state = h_matching_proxy_connection; + break; + + case 't': + header_state = h_matching_transfer_encoding; + break; + + case 'u': + header_state = h_matching_upgrade; + break; + + default: + header_state = h_general; + break; + } + break; + } + + case s_header_field: + { + c = TOKEN(ch); + + if (c) { + switch (header_state) { + case h_general: + break; + + case h_C: + index++; + header_state = (c == 'o' ? h_CO : h_general); + break; + + case h_CO: + index++; + header_state = (c == 'n' ? h_CON : h_general); + break; + + case h_CON: + index++; + switch (c) { + case 'n': + header_state = h_matching_connection; + break; + case 't': + header_state = h_matching_content_length; + break; + default: + header_state = h_general; + break; + } + break; + + /* connection */ + + case h_matching_connection: + index++; + if (index > sizeof(CONNECTION)-1 + || c != CONNECTION[index]) { + header_state = h_general; + } else if (index == sizeof(CONNECTION)-2) { + header_state = h_connection; + } + break; + + /* proxy-connection */ + + case h_matching_proxy_connection: + index++; + if (index > sizeof(PROXY_CONNECTION)-1 + || c != PROXY_CONNECTION[index]) { + header_state = h_general; + } else if (index == sizeof(PROXY_CONNECTION)-2) { + header_state = h_connection; + } + break; + + /* content-length */ + + case h_matching_content_length: + index++; + if (index > sizeof(CONTENT_LENGTH)-1 + || c != CONTENT_LENGTH[index]) { + header_state = h_general; + } else if (index == sizeof(CONTENT_LENGTH)-2) { + header_state = h_content_length; + } + break; + + /* transfer-encoding */ + + case h_matching_transfer_encoding: + index++; + if (index > sizeof(TRANSFER_ENCODING)-1 + || c != TRANSFER_ENCODING[index]) { + header_state = h_general; + } else if (index == sizeof(TRANSFER_ENCODING)-2) { + header_state = h_transfer_encoding; + } + break; + + /* upgrade */ + + case h_matching_upgrade: + index++; + if (index > sizeof(UPGRADE)-1 + || c != UPGRADE[index]) { + header_state = h_general; + } else if (index == sizeof(UPGRADE)-2) { + header_state = h_upgrade; + } + break; + + case h_connection: + case h_content_length: + case h_transfer_encoding: + case h_upgrade: + if (ch != ' ') header_state = h_general; + break; + + default: + assert(0 && "Unknown header_state"); + break; + } + break; + } + + if (ch == ':') { + CALLBACK(header_field); + state = s_header_value_start; + break; + } + + if (ch == CR) { + state = s_header_almost_done; + CALLBACK(header_field); + break; + } + + if (ch == LF) { + CALLBACK(header_field); + state = s_header_field_start; + break; + } + + goto error; + } + + case s_header_value_start: + { + if (ch == ' ') break; + + MARK(header_value); + + state = s_header_value; + index = 0; + + c = LOWER(ch); + + if (ch == CR) { + CALLBACK(header_value); + header_state = h_general; + state = s_header_almost_done; + break; + } + + if (ch == LF) { + CALLBACK(header_value); + state = s_header_field_start; + break; + } + + switch (header_state) { + case h_upgrade: + parser->flags |= F_UPGRADE; + header_state = h_general; + break; + + case h_transfer_encoding: + /* looking for 'Transfer-Encoding: chunked' */ + if ('c' == c) { + header_state = h_matching_transfer_encoding_chunked; + } else { + header_state = h_general; + } + break; + + case h_content_length: + if (ch < '0' || ch > '9') goto error; + parser->content_length = ch - '0'; + break; + + case h_connection: + /* looking for 'Connection: keep-alive' */ + if (c == 'k') { + header_state = h_matching_connection_keep_alive; + /* looking for 'Connection: close' */ + } else if (c == 'c') { + header_state = h_matching_connection_close; + } else { + header_state = h_general; + } + break; + + default: + header_state = h_general; + break; + } + break; + } + + case s_header_value: + { + c = LOWER(ch); + + if (ch == CR) { + CALLBACK(header_value); + state = s_header_almost_done; + break; + } + + if (ch == LF) { + CALLBACK(header_value); + goto header_almost_done; + } + + switch (header_state) { + case h_general: + break; + + case h_connection: + case h_transfer_encoding: + assert(0 && "Shouldn't get here."); + break; + + case h_content_length: + if (ch == ' ') break; + if (ch < '0' || ch > '9') goto error; + parser->content_length *= 10; + parser->content_length += ch - '0'; + break; + + /* Transfer-Encoding: chunked */ + case h_matching_transfer_encoding_chunked: + index++; + if (index > sizeof(CHUNKED)-1 + || c != CHUNKED[index]) { + header_state = h_general; + } else if (index == sizeof(CHUNKED)-2) { + header_state = h_transfer_encoding_chunked; + } + break; + + /* looking for 'Connection: keep-alive' */ + case h_matching_connection_keep_alive: + index++; + if (index > sizeof(KEEP_ALIVE)-1 + || c != KEEP_ALIVE[index]) { + header_state = h_general; + } else if (index == sizeof(KEEP_ALIVE)-2) { + header_state = h_connection_keep_alive; + } + break; + + /* looking for 'Connection: close' */ + case h_matching_connection_close: + index++; + if (index > sizeof(CLOSE)-1 || c != CLOSE[index]) { + header_state = h_general; + } else if (index == sizeof(CLOSE)-2) { + header_state = h_connection_close; + } + break; + + case h_transfer_encoding_chunked: + case h_connection_keep_alive: + case h_connection_close: + if (ch != ' ') header_state = h_general; + break; + + default: + state = s_header_value; + header_state = h_general; + break; + } + break; + } + + case s_header_almost_done: + header_almost_done: + { + STRICT_CHECK(ch != LF); + + state = s_header_field_start; + + switch (header_state) { + case h_connection_keep_alive: + parser->flags |= F_CONNECTION_KEEP_ALIVE; + break; + case h_connection_close: + parser->flags |= F_CONNECTION_CLOSE; + break; + case h_transfer_encoding_chunked: + parser->flags |= F_CHUNKED; + break; + default: + break; + } + break; + } + + case s_headers_almost_done: + headers_almost_done: + { + STRICT_CHECK(ch != LF); + + if (parser->flags & F_TRAILING) { + /* End of a chunked request */ + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + break; + } + + nread = 0; + + if (parser->flags & F_UPGRADE || parser->method == HTTP_CONNECT) { + parser->upgrade = 1; + } + + /* Here we call the headers_complete callback. This is somewhat + * different than other callbacks because if the user returns 1, we + * will interpret that as saying that this message has no body. This + * is needed for the annoying case of receiving a response to a HEAD + * request. + */ + if (settings->on_headers_complete) { + switch (settings->on_headers_complete(parser)) { + case 0: + break; + + case 1: + parser->flags |= F_SKIPBODY; + break; + + default: + parser->state = state; + return p - data; /* Error */ + } + } + + /* Exit, the rest of the connect is in a different protocol. */ + if (parser->upgrade) { + CALLBACK2(message_complete); + return (p - data); + } + + if (parser->flags & F_SKIPBODY) { + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + } else if (parser->flags & F_CHUNKED) { + /* chunked encoding - ignore Content-Length header */ + state = s_chunk_size_start; + } else { + if (parser->content_length == 0) { + /* Content-Length header given but zero: Content-Length: 0\r\n */ + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + } else if (parser->content_length > 0) { + /* Content-Length header given and non-zero */ + state = s_body_identity; + } else { + if (parser->type == HTTP_REQUEST || http_should_keep_alive(parser)) { + /* Assume content-length 0 - read the next */ + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + } else { + /* Read body until EOF */ + state = s_body_identity_eof; + } + } + } + + break; + } + + case s_body_identity: + to_read = MIN((size_t)(pe - p), parser->content_length); + if (to_read > 0) { + if (settings->on_body) settings->on_body(parser, p, to_read); + p += to_read - 1; + parser->content_length -= to_read; + if (parser->content_length == 0) { + CALLBACK2(message_complete); + state = NEW_MESSAGE(); + } + } + break; + + /* read until EOF */ + case s_body_identity_eof: + to_read = pe - p; + if (to_read > 0) { + if (settings->on_body) settings->on_body(parser, p, to_read); + p += to_read - 1; + } + break; + + case s_chunk_size_start: + { + assert(nread == 1); + assert(parser->flags & F_CHUNKED); + + c = unhex[(unsigned char)ch]; + if (c == -1) goto error; + parser->content_length = c; + state = s_chunk_size; + break; + } + + case s_chunk_size: + { + assert(parser->flags & F_CHUNKED); + + if (ch == CR) { + state = s_chunk_size_almost_done; + break; + } + + c = unhex[(unsigned char)ch]; + + if (c == -1) { + if (ch == ';' || ch == ' ') { + state = s_chunk_parameters; + break; + } + goto error; + } + + parser->content_length *= 16; + parser->content_length += c; + break; + } + + case s_chunk_parameters: + { + assert(parser->flags & F_CHUNKED); + /* just ignore this shit. TODO check for overflow */ + if (ch == CR) { + state = s_chunk_size_almost_done; + break; + } + break; + } + + case s_chunk_size_almost_done: + { + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + + nread = 0; + + if (parser->content_length == 0) { + parser->flags |= F_TRAILING; + state = s_header_field_start; + } else { + state = s_chunk_data; + } + break; + } + + case s_chunk_data: + { + assert(parser->flags & F_CHUNKED); + + to_read = MIN(pe - p, (int64_t)(parser->content_length)); + + if (to_read > 0) { + if (settings->on_body) settings->on_body(parser, p, to_read); + p += to_read - 1; + } + + if (to_read == parser->content_length) { + state = s_chunk_data_almost_done; + } + + parser->content_length -= to_read; + break; + } + + case s_chunk_data_almost_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != CR); + state = s_chunk_data_done; + break; + + case s_chunk_data_done: + assert(parser->flags & F_CHUNKED); + STRICT_CHECK(ch != LF); + state = s_chunk_size_start; + break; + + default: + assert(0 && "unhandled state"); + goto error; + } + } + + CALLBACK_NOCLEAR(header_field); + CALLBACK_NOCLEAR(header_value); + CALLBACK_NOCLEAR(fragment); + CALLBACK_NOCLEAR(query_string); + CALLBACK_NOCLEAR(path); + CALLBACK_NOCLEAR(url); + + parser->state = state; + parser->header_state = header_state; + parser->index = (unsigned char)index; + parser->nread = (unsigned char)nread; + + return len; error: - parser->state = s_dead; - return (p - data); + parser->state = s_dead; + return (p - data); } int http_should_keep_alive (http_parser *parser) { - if (parser->http_major > 0 && parser->http_minor > 0) { - /* HTTP/1.1 */ - if (parser->flags & F_CONNECTION_CLOSE) { - return 0; - } else { - return 1; - } - } else { - /* HTTP/1.0 or earlier */ - if (parser->flags & F_CONNECTION_KEEP_ALIVE) { - return 1; - } else { - return 0; - } - } + if (parser->http_major > 0 && parser->http_minor > 0) { + /* HTTP/1.1 */ + if (parser->flags & F_CONNECTION_CLOSE) { + return 0; + } else { + return 1; + } + } else { + /* HTTP/1.0 or earlier */ + if (parser->flags & F_CONNECTION_KEEP_ALIVE) { + return 1; + } else { + return 0; + } + } } const char * http_method_str (enum http_method m) { - return method_strings[m]; + return method_strings[m]; } void http_parser_init (http_parser *parser, enum http_parser_type t) { - parser->type = t; - parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); - parser->nread = 0; - parser->upgrade = 0; - parser->flags = 0; - parser->method = 0; + parser->type = t; + parser->state = (t == HTTP_REQUEST ? s_start_req : (t == HTTP_RESPONSE ? s_start_res : s_start_req_or_res)); + parser->nread = 0; + parser->upgrade = 0; + parser->flags = 0; + parser->method = 0; } diff --git a/content/assignments/async-web-server/src/http-parser/http_parser.h b/content/assignments/async-web-server/src/http-parser/http_parser.h index 21e30d1d9c..804ab4969d 100644 --- a/content/assignments/async-web-server/src/http-parser/http_parser.h +++ b/content/assignments/async-web-server/src/http-parser/http_parser.h @@ -52,7 +52,7 @@ typedef int ssize_t; #endif -/* Maximium header size allowed */ +/* Maximum header size allowed */ #define HTTP_MAX_HEADER_SIZE (80*1024) diff --git a/content/assignments/lambda-function-loader/tests/checker.sh b/content/assignments/lambda-function-loader/tests/checker.sh index d1af4b57ba..f69a1f09ba 100755 --- a/content/assignments/lambda-function-loader/tests/checker.sh +++ b/content/assignments/lambda-function-loader/tests/checker.sh @@ -82,7 +82,7 @@ gen_big_test() { elif [ $((CLIENT_NUM%4)) -eq 1 ]; then cat "${BIG_DIR}/test_${CLIENT_NUM}" >> "$GEN_REF_FILE" elif [ $((CLIENT_NUM%4)) -eq 2 ]; then - echo "Reseted the counter!" >> "$GEN_REF_FILE" + echo "Reset the counter!" >> "$GEN_REF_FILE" else echo "Error: $CHECKER_DIR/libfictional.so reset could not be executed." >> "$GEN_REF_FILE" fi diff --git a/content/assignments/lambda-function-loader/tests/special.c b/content/assignments/lambda-function-loader/tests/special.c index 9fd53da954..b11a61c68b 100644 --- a/content/assignments/lambda-function-loader/tests/special.c +++ b/content/assignments/lambda-function-loader/tests/special.c @@ -26,5 +26,5 @@ void reset(void) { /* Let's erase the history, shall we? */ counter = 0; - printf("Reseted the counter!\n"); + printf("Reset the counter!\n"); } diff --git a/content/assignments/minishell/tests/_test/run_test.sh b/content/assignments/minishell/tests/_test/run_test.sh index 6569fe2dba..8287b0ef0b 100755 --- a/content/assignments/minishell/tests/_test/run_test.sh +++ b/content/assignments/minishell/tests/_test/run_test.sh @@ -129,7 +129,7 @@ execute_cmd() { mkdir -p "${OUT_DIR}" && cd "${OUT_DIR}" &>"$LOG_FILE" || exit 1 # shellcheck disable=SC2086 timeout "$TEST_TIMEOUT" $BUFFERING_WRAPPER $EXEC <"${INPUT}" &>"$OUTPUT" - # Ocasionally, in a virtualized environment, the diff that compares the + # Occasionally, in a virtualized environment, the diff that compares the # target implementation with the reference output starts before the # target implementation has finished writing files to disk. Handle this # by mandating that all I/O buffers be flushed. diff --git a/content/assignments/minishell/util/parser/parser.h b/content/assignments/minishell/util/parser/parser.h index 9b81fca7bf..6e2e1f8e3e 100644 --- a/content/assignments/minishell/util/parser/parser.h +++ b/content/assignments/minishell/util/parser/parser.h @@ -157,7 +157,7 @@ typedef enum { * (the father of the current node in the parse tree) * The root of the tree has up == NULL - * The parsed expressions do not contain parantheses, this means that + * The parsed expressions do not contain parentheses, this means that * the following holds: * for any op_lower that has a lower priority than op, there is no * parent in the tree with op == op_lower @@ -194,7 +194,7 @@ void parse_error(const char *str, const int where); /* * Call this to parse a line - * line must point to a string containig a single line + * line must point to a string containing a single line * The line must end with "\r\n\0" or "\n\0" or "\0" * (*root) must point to NULL ((*root) == NULL) diff --git a/content/assignments/minishell/util/parser/parser.l b/content/assignments/minishell/util/parser/parser.l index c05584a2b7..4fcd3e5de9 100644 --- a/content/assignments/minishell/util/parser/parser.l +++ b/content/assignments/minishell/util/parser/parser.l @@ -11,7 +11,7 @@ #ifdef _MSC_VER /* Speaking of MS, they do not implement standard C; * YY_USE_CONST is defined only if __STDC__ is defined; - * here is alread too late to redefine YY_USE_CONST so + * here is already too late to redefine YY_USE_CONST so * we use pragma instead ^^. */ #pragma warning(disable:4090) diff --git a/content/assignments/minishell/util/parser/parser.y b/content/assignments/minishell/util/parser/parser.y index 3cd5984858..9e69222221 100644 --- a/content/assignments/minishell/util/parser/parser.y +++ b/content/assignments/minishell/util/parser/parser.y @@ -177,7 +177,7 @@ static word_t * add_part_to_word(word_t * w, word_t * lst) assert(w != NULL); /* - we could insert at the beginnig and then invert the list + we could insert at the beginning and then invert the list but this would make the code a bit more complicated thus, we assume we have small lists and O(n*n) is acceptable */ diff --git a/content/assignments/parallel-firewall/src/ring_buffer.h b/content/assignments/parallel-firewall/src/ring_buffer.h index b3b66afa90..82be3d86d1 100644 --- a/content/assignments/parallel-firewall/src/ring_buffer.h +++ b/content/assignments/parallel-firewall/src/ring_buffer.h @@ -15,7 +15,7 @@ typedef struct so_ring_buffer_t { size_t len; size_t cap; - /* TODO: Add syncronization primitives */ + /* TODO: Add synchronization primitives */ } so_ring_buffer_t; int ring_buffer_init(so_ring_buffer_t *rb, size_t cap); diff --git a/content/assignments/parallel-firewall/tests/checker.py b/content/assignments/parallel-firewall/tests/checker.py index ef099af05b..d87a914e25 100644 --- a/content/assignments/parallel-firewall/tests/checker.py +++ b/content/assignments/parallel-firewall/tests/checker.py @@ -142,12 +142,12 @@ def file_line_count(file_path: str) -> int: def line_count_probe_check(probe: List[int]) -> bool: - double_occurences = 0 + double_occurrences = 0 for i in range(1, len(probe)): if probe[i] == probe[i - 1] and probe[i] != 0 and probe[i] not in TEST_SIZES: - double_occurences += 1 + double_occurrences += 1 - return double_occurences / len(probe) <= 0.5 + return double_occurrences / len(probe) <= 0.5 def file_exists_probe_check(probe: List[bool]) -> bool: diff --git a/gen-view.py b/gen-view.py index 3f3fc9b174..ddb49ee935 100644 --- a/gen-view.py +++ b/gen-view.py @@ -17,7 +17,7 @@ questionsDir = f"{viewDir}/questions" -def hypenate(text: str) -> str: +def hyphenate(text: str) -> str: return "-".join(text.strip().split(" ")).lower() @@ -92,8 +92,8 @@ def setup_overview(): """ Copy the overview.md file for each chapter to the .view directory. """ - hypenChapters = [hypenate(c) for c in CHAPTERS] - for c in hypenChapters: + hyphenChapters = [hyphenate(c) for c in CHAPTERS] + for c in hyphenChapters: # FIXME: We use "." instead of CHAPTERS_PATH to account for the segregated chapters. # This is a temporary solution until all chapters are merged under CHAPTERS_PATH. for root, _, files in os.walk("."): @@ -102,7 +102,7 @@ def setup_overview(): print(f"Copying {root}/overview.md to {dst}") os.popen(f"cp {os.path.join(root, 'overview.md')} {dst}") - for c in hypenChapters: + for c in hyphenChapters: if not os.path.isfile(f"{viewDir}/{c}-overview.md"): continue @@ -157,11 +157,11 @@ def solve_links(filename: str, fileToLab: dict) -> str: elif "guides/" in sourceFile: prefix = "guide-" - # Get the first line of the file to extract the chapter in hypenated format + # Get the first line of the file to extract the chapter in hyphenated format try: with open(filepath) as f: title = f.readline().strip("#").replace("`", "").replace(":", "") - subchapter = prefix + hypenate(title) + subchapter = prefix + hyphenate(title) except: print(f"Error: Could not solve link to {filepath} for {filename}") continue