From 418462208a10d1d186454d834115f8517ea10007 Mon Sep 17 00:00:00 2001 From: Turiiya <34311583+ttytm@users.noreply.github.com> Date: Sun, 24 Mar 2024 18:54:39 +0100 Subject: [PATCH] vlib.x: fix typos, uniformize readme formatting (#21085) --- vlib/x/crypto/chacha20/README.md | 9 ++- vlib/x/crypto/chacha20/chacha.v | 8 +-- vlib/x/crypto/chacha20poly1305/README.md | 37 ++++++------ .../chacha20poly1305/chacha20poly1305.v | 6 +- vlib/x/crypto/poly1305/README.md | 8 +-- vlib/x/crypto/poly1305/poly1305.v | 4 +- vlib/x/crypto/poly1305/usage_test.v | 6 +- vlib/x/crypto/sm4/sm4.v | 10 ++-- vlib/x/crypto/sm4/sm4_test.v | 4 +- vlib/x/json2/README.md | 12 +++- vlib/x/json2/count.v | 2 +- vlib/x/sessions/README.md | 47 +++++++++------ vlib/x/sessions/sessions.v | 4 +- vlib/x/templating/dtm/README.md | 59 ++++++++++--------- .../templating/dtm/dynamic_template_manager.v | 20 +++---- ...namic_template_manager_cache_system_test.v | 4 +- vlib/x/vweb/README.md | 52 ++++++++++++++-- vlib/x/vweb/assets/README.md | 27 ++++++--- vlib/x/vweb/context.v | 6 +- vlib/x/vweb/static_handler.v | 2 +- vlib/x/vweb/tests/large_payload_test.v | 2 +- vlib/x/vweb/tests/static_handler_test.v | 8 +-- vlib/x/vweb/tests/testdata/unknown_mime.what | 1 + vlib/x/vweb/tests/testdata/unkown_mime.what | 1 - vlib/x/vweb/vweb.v | 8 +-- 25 files changed, 213 insertions(+), 134 deletions(-) create mode 100644 vlib/x/vweb/tests/testdata/unknown_mime.what delete mode 100644 vlib/x/vweb/tests/testdata/unkown_mime.what diff --git a/vlib/x/crypto/chacha20/README.md b/vlib/x/crypto/chacha20/README.md index b68ed3fc4..29170c1f7 100644 --- a/vlib/x/crypto/chacha20/README.md +++ b/vlib/x/crypto/chacha20/README.md @@ -1,13 +1,12 @@ # module chacha20 -chacha20 -------- +## chacha20 Chacha20 (and XChacha20) stream cipher encryption algorithm in pure V. Its mostly based on [RFC 8439](https://datatracker.ietf.org/doc/html/rfc8439) and inspired by Go version of the same library. -Examples --------- +## Examples + ```v module main @@ -31,4 +30,4 @@ fn main() { // should true assert input == input_back } -``` \ No newline at end of file +``` diff --git a/vlib/x/crypto/chacha20/chacha.v b/vlib/x/crypto/chacha20/chacha.v index 7122a88b6..6adfe1a1d 100644 --- a/vlib/x/crypto/chacha20/chacha.v +++ b/vlib/x/crypto/chacha20/chacha.v @@ -2,7 +2,7 @@ // Use of this source code is governed by an MIT license // that can be found in the LICENSE file. // -// Chacha20 symetric key stream cipher encryption based on RFC 8439 +// Chacha20 symmetric key stream cipher encryption based on RFC 8439 module chacha20 import math.bits @@ -32,8 +32,8 @@ struct Cipher { mut: // internal's of ChaCha20 states, ie, 16 of u32 words, 4 of ChaCha20 constants, // 8 word (32 bytes) of keys, 3 word (24 bytes) of nonces and 1 word of counter - key [8]u32 - nonce [3]u32 + key [8]u32 + nonce [3]u32 counter u32 overflow bool // internal buffer for storing key stream results @@ -72,7 +72,7 @@ pub fn decrypt(key []u8, nonce []u8, ciphertext []u8) ![]u8 { } // xor_key_stream xors each byte in the given slice in the src with a byte from the -// cipher's key stream. It fullfills `cipher.Stream` interface. It encrypts the plaintext message +// cipher's key stream. It fulfills `cipher.Stream` interface. It encrypts the plaintext message // in src and stores the ciphertext result in dst in a single run of encryption. // You must never use the same (key, nonce) pair more than once for encryption. // This would void any confidentiality guarantees for the messages encrypted with the same nonce and key. diff --git a/vlib/x/crypto/chacha20poly1305/README.md b/vlib/x/crypto/chacha20poly1305/README.md index d59887f89..01e1dacc7 100644 --- a/vlib/x/crypto/chacha20poly1305/README.md +++ b/vlib/x/crypto/chacha20poly1305/README.md @@ -3,36 +3,37 @@ Chacha20Poly1305 Authenticated Encryption with Additional Data (AEAD) module for V Language This module provides authenticated encryption with additional data (AEAD) algorithm in V Language. -Its backed by experimental `x.crypto.chacha20` symetric key stream cipher encryption +Its backed by experimental `x.crypto.chacha20` symmetric key stream cipher encryption module and `x.crypto.poly1305` message authentication code (MAC) module. > [!Warning] > This is an absolutely experimental module, which is subject to change. -> Please use it carefully, thoroughly and wisely. +> Please use it carefully, thoroughly and wisely. + +## Examples -Examples --------- ```v import encoding.hex import x.crypto.chacha20poly1305 fn main() { - // plaintext message to be encrypted and authenticated - message := "Ladies and Gentlemen of the class of '99: If I could offer you only \ - one tip for the future, sunscreen would be it.".bytes() + // plaintext message to be encrypted and authenticated + message := "Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it." + .bytes() - // sets your secure random key - key := hex.decode('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f')! - // give yours nonce - nonce := hex.decode('070000004041424344454647')! - // yours additional data - aad := hex.decode('50515253c0c1c2c3c4c5c6c7')! + // sets your secure random key + key := hex.decode('808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f')! + // give yours nonce + nonce := hex.decode('070000004041424344454647')! + // yours additional data + aad := hex.decode('50515253c0c1c2c3c4c5c6c7')! - // lets doing authenticated encryption - ciphertext := chacha20poly1305.encrypt(message, key, nonce, aad)! + // lets doing authenticated encryption + ciphertext := chacha20poly1305.encrypt(message, key, nonce, aad)! - // lets perform decryption back - plaintext := chacha20poly1305.decrypt(ciphertext, key, nonce, aad)! + // lets perform decryption back + plaintext := chacha20poly1305.decrypt(ciphertext, key, nonce, aad)! - assert plaintext == message + assert plaintext == message } +``` diff --git a/vlib/x/crypto/chacha20poly1305/chacha20poly1305.v b/vlib/x/crypto/chacha20poly1305/chacha20poly1305.v index 6327d627e..00eb60bfd 100644 --- a/vlib/x/crypto/chacha20poly1305/chacha20poly1305.v +++ b/vlib/x/crypto/chacha20poly1305/chacha20poly1305.v @@ -41,7 +41,7 @@ pub interface AEAD { // key_size is the size of key (in bytes) which the Chacha20Poly1305 AEAD accepts. pub const key_size = 32 -// nonce_size is the size of the standar nonce (in bytes) which the Chacha20Poly1305 AEAD accepts. +// nonce_size is the size of the standard nonce (in bytes) which the Chacha20Poly1305 AEAD accepts. pub const nonce_size = 12 // nonce_size is the size of the extended nonce (in bytes) which the Chacha20Poly1305 AEAD accepts. pub const x_nonce_size = 24 @@ -136,7 +136,7 @@ fn (c Chacha20Poly1305) encrypt_generic(plaintext []u8, nonce []u8, ad []u8) ![] s.xor_key_stream(mut ciphertext, plaintext) // Finally, the Poly1305 function is called with the generated Poly1305 one-time key - // calculated above, and a message constructed as descibed in + // calculated above, and a message constructed as described in // https://datatracker.ietf.org/doc/html/rfc8439#section-2.8 mut constructed_msg := []u8{} poly1305_construct_msg(mut constructed_msg, ad, ciphertext) @@ -155,7 +155,7 @@ fn (c Chacha20Poly1305) encrypt_generic(plaintext []u8, nonce []u8, ad []u8) ![] } // decrypt decrypts ciphertext along with provided nonce and additional data. -// Decryption is similar with the encryption processs with slight differences in: +// Decryption is similar with the encryption process with slight differences in: // The roles of ciphertext and plaintext are reversed, so the ChaCha20 encryption // function is applied to the ciphertext, producing the plaintext. // The Poly1305 function is still run on the AAD and the ciphertext, not the plaintext. diff --git a/vlib/x/crypto/poly1305/README.md b/vlib/x/crypto/poly1305/README.md index b23b56612..1f387b0a1 100644 --- a/vlib/x/crypto/poly1305/README.md +++ b/vlib/x/crypto/poly1305/README.md @@ -6,15 +6,15 @@ Poly1305 takes a 32-byte one-time key and a message and produces a This module provides generic `poly1305` message authentication code (MAC) module in pure V. -As a note, a key must only be used for a single message. Authenticating two different +As a note, **a key must only be used for a single message**. Authenticating two different messages with the same key allows an attacker to forge authenticators for other messages with the same key. > [!Warning] > This is an experimental module, which is subject to change, please use it carefully and thoroughly -Examples --------- +## Examples + ```v module main @@ -36,4 +36,4 @@ fn main() { status := poly1305.verify_tag(out, msg, key) assert status == true } -``` \ No newline at end of file +``` diff --git a/vlib/x/crypto/poly1305/poly1305.v b/vlib/x/crypto/poly1305/poly1305.v index f60e5e1f5..be84b0a5c 100644 --- a/vlib/x/crypto/poly1305/poly1305.v +++ b/vlib/x/crypto/poly1305/poly1305.v @@ -73,7 +73,7 @@ pub fn create_tag(mut out []u8, msg []u8, key []u8) ! { } // verify_tag verifies the tag is a valid message authentication code for the msg -// compared to the tag outputed from the calculated process. +// compared to the tag output from the calculated process. // It returns `true` if two tags is matching, `false` otherwise. pub fn verify_tag(tag []u8, msg []u8, key []u8) bool { mut po := new(key) or { panic(err) } @@ -369,7 +369,7 @@ fn poly1305_squeeze(mut h Uint192, t [4]u64) { ac, c = ac.add_128_checked(cc, c) cc = shift_right_by2(mut cc) - // once agains + // once again ac, c = ac.add_128_checked(cc, 0) // updates accumulator h = ac diff --git a/vlib/x/crypto/poly1305/usage_test.v b/vlib/x/crypto/poly1305/usage_test.v index b41520b88..849b24f1b 100644 --- a/vlib/x/crypto/poly1305/usage_test.v +++ b/vlib/x/crypto/poly1305/usage_test.v @@ -4,7 +4,7 @@ import x.crypto.poly1305 // perform test for oneshot function for poly1305 mac creation and verifying it. fn test_fn_create_and_verify_tag() ! { // Sample messages from RFC A.3 Test vector 2 - // set yur secure key + // set secure key key := hex.decode('0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e')! // messages to be authenticated msg := 'Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to' @@ -25,7 +25,7 @@ fn test_fn_create_and_verify_tag() ! { // perform test for instance based method. fn test_create_and_verify_tag_with_poly1305_instance() ! { // Sample messages from RFC A.3 Test vector 2 - // set yur secure key + // set secure key key := hex.decode('0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e')! // messages to be authenticated msg := 'Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to' @@ -54,7 +54,7 @@ fn test_create_and_verify_tag_with_poly1305_instance() ! { // updates state by multiples block of messages by calling .update method of the Poly1305 instance fn test_create_and_verify_tag_with_poly1305_instance_in_incremental_updates() ! { // Sample messages from RFC A.3 Test vector 2 - // set yur secure key + // set secure key key := hex.decode('0000000000000000000000000000000036e5f6b5c5e06070f0efca96227a863e')! // messages to be authenticated // msg := 'Any submission to the IETF intended by the Contributor for publication as all or part of an IETF Internet-Draft or RFC and any statement made within the context of an IETF activity is considered an "IETF Contribution". Such statements include oral statements in IETF sessions, as well as written and electronic communications made at any time or place, which are addressed to' diff --git a/vlib/x/crypto/sm4/sm4.v b/vlib/x/crypto/sm4/sm4.v index 703d45cd7..cc78a7346 100644 --- a/vlib/x/crypto/sm4/sm4.v +++ b/vlib/x/crypto/sm4/sm4.v @@ -254,7 +254,7 @@ fn big_endian_put_u128_fixed_reverse(mut b [16]u8, v [4]u32) { } } -// sm4_tl performance the "T algorithm" == "t algorithm" + "L algorithm" funciton. +// sm4_tl performance the "T algorithm" == "t algorithm" + "L algorithm" function. @[direct_array_access; inline] fn sm4_tl(ka u32) u32 { mut a := [4]u8{} @@ -369,13 +369,13 @@ pub fn new_cipher(mode Mode, key []u8) !&SM4Cipher { } // crypt_ecb SM4-ECB block encryption/decryption -// `input` must be padded to mutiple of 16 bytes. +// `input` must be padded to multiple of 16 bytes. // `output` must be exactly the same length as `input`. @[direct_array_access] pub fn (c &SM4Cipher) crypt_ecb(input []u8, mut output []u8) ! { mut length := input.len if length & 0x0f != 0 || length == 0 { - return error('input must be padded to mutiple of 16 bytes') + return error('input must be padded to multiple of 16 bytes') } if length != output.len { return error('output must be exactly the same length as input') @@ -397,14 +397,14 @@ pub fn (c &SM4Cipher) crypt_ecb(input []u8, mut output []u8) ! { // crypt_cbc SM4-CBC buffer encryption/decryption // `iv` is a 16 bytes Initialization Vector. -// `input` must be padded to mutiple of 16 bytes. +// `input` must be padded to multiple of 16 bytes. // `output` must be exactly the same length as `input`. @[direct_array_access] pub fn (c &SM4Cipher) crypt_cbc(mut iv []u8, input []u8, mut output []u8) ! { mut idx := 0 mut length := input.len if length & 0x0f != 0 || length == 0 { - return error('input must be padded to mutiple of 16 bytes') + return error('input must be padded to multiple of 16 bytes') } if length != output.len { return error('output must be exactly the same length as input') diff --git a/vlib/x/crypto/sm4/sm4_test.v b/vlib/x/crypto/sm4/sm4_test.v index 536f4654c..adc26f60c 100644 --- a/vlib/x/crypto/sm4/sm4_test.v +++ b/vlib/x/crypto/sm4/sm4_test.v @@ -171,7 +171,7 @@ fn test_sm4_wrong_length() ! { mut c1 := sm4.new_cipher(.sm4_encrypt, [u8(0xff)].repeat(16))! c1.crypt_ecb([u8(0xff)].repeat(111), mut output) or { fail_flag = true - assert err.msg() == 'input must be padded to mutiple of 16 bytes' + assert err.msg() == 'input must be padded to multiple of 16 bytes' } assert fail_flag @@ -198,7 +198,7 @@ fn test_sm4_wrong_length() ! { mut c4 := sm4.new_cipher(.sm4_encrypt, [u8(0xff)].repeat(16))! c4.crypt_cbc(mut [u8(0xff)].repeat(16), [u8(0xff)].repeat(111), mut output) or { fail_flag = true - assert err.msg() == 'input must be padded to mutiple of 16 bytes' + assert err.msg() == 'input must be padded to multiple of 16 bytes' } assert fail_flag diff --git a/vlib/x/json2/README.md b/vlib/x/json2/README.md index 9c5ff07fb..9f0285fa6 100644 --- a/vlib/x/json2/README.md +++ b/vlib/x/json2/README.md @@ -4,6 +4,7 @@ `x.json2` is an experimental JSON parser written from scratch on V. ## Usage + #### encode[T] ```v @@ -55,6 +56,7 @@ fn main() { */ } ``` + decode[T] is smart and can auto-convert the types of struct fields - this means examples below will have the same result @@ -78,7 +80,9 @@ fn main() { raw_product := json2.raw_decode(resp.body)! } ``` + #### Casting `Any` type / Navigating + ```v import x.json2 import net.http @@ -96,7 +100,9 @@ fn main() { year := data['year'].int() // 2000 } ``` + #### Constructing an `Any` type + ```v import x.json2 @@ -127,7 +133,9 @@ fn main() { //} } ``` + ### Null Values + `x.json2` has a separate `Null` type for differentiating an undefined value and a null value. To verify that the field you're accessing is a `Null`, use `[typ] is json2.Null`. @@ -142,16 +150,18 @@ fn (mut p Person) from_json(f json2.Any) { ``` ## Casting a value to an incompatible type + `x.json2` provides methods for turning `Any` types into usable types. The following list shows the possible outputs when casting a value to an incompatible type. 1. Casting non-array values as array (`arr()`) will return an array with the value as the content. 2. Casting non-map values as map (`as_map()`) will return a map with the value as the content. 3. Casting non-string values to string (`str()`) will return the -JSON string representation of the value. + JSON string representation of the value. 4. Casting non-numeric values to int/float (`int()`/`i64()`/`f32()`/`f64()`) will return zero. ## Encoding using string builder instead of []u8 + To be more performant, `json2`, in PR 20052, decided to use buffers directly instead of Writers. If you want to use Writers you can follow the steps below: diff --git a/vlib/x/json2/count.v b/vlib/x/json2/count.v index 0984fb4c3..f5cda3c2c 100644 --- a/vlib/x/json2/count.v +++ b/vlib/x/json2/count.v @@ -17,7 +17,7 @@ fn (mut count Count) reset_total() { count.total = 0 } -// count_chars count json sizen whithout new encode +// count_chars count json sizen without new encode fn (mut count Count) count_chars[T](val T) { $if val is $option { workaround := val diff --git a/vlib/x/sessions/README.md b/vlib/x/sessions/README.md index 10b98ed8a..e3c3066e5 100644 --- a/vlib/x/sessions/README.md +++ b/vlib/x/sessions/README.md @@ -4,14 +4,14 @@ A sessions module for web projects. ## Usage -The sessions module provides an implemention for [session stores](#custom-stores). +The sessions module provides an implementation for [session stores](#custom-stores). The session store handles the saving, storing and retrieving of data. You can either use a store directly yourself, or you can use the `session.Sessions` struct -which is easier to use since it also handles session verification and intergrates nicely +which is easier to use since it also handles session verification and integrates nicely with vweb. If you want to use `session.Sessions` in your web app the session id's will be -stored using cookies. The best way to get started is to follow the +stored using cookies. The best way to get started is to follow the [getting started](#getting-started) section. Otherwise have a look at the [advanced usage](#advanced-usage) section. @@ -23,10 +23,11 @@ for examples without `x.vweb`. To start using sessions in vweb embed `sessions.CurrentSession` on the Context struct and add `sessions.Sessions` to the app struct. We must also pass the type -of our session data. +of our session data. For any further example code we will use the `User` struct. **Example:** + ```v ignore import x.sessions import x.vweb @@ -52,17 +53,17 @@ pub mut: } ``` -Next we need to create the `&sessions.Sessions[User]` instance for our app. This -struct provides functionality to easier manage sessions in a vweb app. +Next we need to create the `&sessions.Sessions[User]` instance for our app. This +struct provides functionality to easier manage sessions in a vweb app. ### Session Stores To create `sessions.Sessions` We must specify a "store" which handles the session data. Currently vweb provides two options for storing session data: -1. The `MemoryStore[T]` stores session data in memory only using the `map` datatype. +1. The `MemoryStore[T]` stores session data in memory only using the `map` datatype. 2. The `DBStore[T]` stores session data in a database by encoding the session data to JSON. -It will create the table `DBStoreSessions` in your database where the session data will be stored. + It will create the table `DBStoreSessions` in your database, to store the session data. It is possible to create your own session store, see [custom stores](#custom-stores). @@ -71,6 +72,7 @@ It is possible to create your own session store, see [custom stores](#custom-sto For this example we will use the memory store. **Example:** + ```v ignore fn main() { mut app := &App{ @@ -78,14 +80,14 @@ fn main() { // use your own secret which will be used to verify session id's secret: 'my secret'.bytes() } - + vweb.run[App, Context](mut app, 8080) } ``` ### Middleware -The `sessions.vweb2_middleware` module provides a middleware handler. This handler will execute +The `sessions.vweb2_middleware` module provides a middleware handler. This handler will execute before your own route handlers and will verify the current session and fetch any associated session data and load it into `sessions.CurrentSession`, which is embedded on the Context struct. @@ -94,6 +96,7 @@ session data and load it into `sessions.CurrentSession`, which is embedded on th > and loaded correctly. **Example:** + ```v ignore // add this import at the top of your file import x.sessions.vweb2_middleware @@ -116,7 +119,7 @@ fn main() { // register the sessions middleware app.use(vweb2_middleware.create[User, Context](mut app.sessions)) - + vweb.run[App, Context](mut app, 8080) } ``` @@ -132,6 +135,7 @@ access any session data via `ctx.session_data`. This field is an option, it will if no data is set. **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { // check if a user is logged in @@ -149,11 +153,12 @@ pub fn (app &App) index(mut ctx Context) vweb.Result { You can use the `save` method to update and save any session data. When the user logs in, the `save` method is called and a new session id is generated -and set as cookie. Assuming there wasn't already a session going on. If you want to +and set as cookie. Assuming there wasn't already a session going on. If you want to be sure that a new session id is generated when you save data, you can use the `resave` method. This method will save the data and *always* set a new session id. **Example:** + ```v ignore pub fn (mut app App) login(mut ctx Context) vweb.Result { // set a session id cookie and save data for the new user @@ -172,6 +177,7 @@ you can use this route via `http://localhost:8080/save?name=myname`. And if the query parameter is not passed an error 400 (bad request) is returned. **Example:** + ```v ignore pub fn (mut app App) save(mut ctx Context) vweb.Result { // check if there is a session @@ -192,11 +198,12 @@ pub fn (mut app App) save(mut ctx Context) vweb.Result { #### Destroying data / logging out -If a user logs out you can use the `logout` method to destroy the session data and -clear the session id cookie. If you only want to destroy the session data use the `destroy` +If a user logs out you can use the `logout` method to destroy the session data and +clear the session id cookie. If you only want to destroy the session data use the `destroy` method. **Example:** + ```v ignore pub fn (mut app App) logout(mut ctx Context) vweb.Result { app.sessions.logout(mut ctx) or { return ctx.server_error('could not logout, please try again') } @@ -209,6 +216,7 @@ pub fn (mut app App) logout(mut ctx Context) vweb.Result { Change the `cookie_options` field to modify how the session cookie is stored. **Example:** + ```v ignore mut app := &App{ sessions: &sessions.Sessions[User]{ @@ -234,8 +242,8 @@ By setting `save_uninitialized` to `true` a session cookie will always be set, even if there is no data for the session yet. This is useful when you need session data to be always available. -Or, for example, you could use pre-sessions to mittigate login-csrf, -since you can bind a csrf-token to the "pre-session" id. Then when the user logs +Or, for example, you could use pre-sessions to mitigate login-csrf, +since you can bind a csrf-token to the "pre-session" id. Then when the user logs in, you can set a new session id with `resave`.. ## Advanced Usage @@ -246,6 +254,7 @@ instance of a `Store` and directly interact with it. First we create an instance of the `MemoryStore` and pass the user struct as data type. **Example:** + ```v import x.sessions @@ -272,6 +281,7 @@ The session module provides a function for generating a new signed session id and for verifying a signed session id. You can ofcourse generate your own session id's. **Example:** + ```v ignore // fn main // generate a new session id and sign it @@ -288,6 +298,7 @@ We can retrieve the saved user and verify that the data we saved can be retrieve from the verified session id. **Example:** + ```v ignore // fn main // pass `max_age = 0` to ignore the expiration time. @@ -301,7 +312,7 @@ if saved_user := store.get(verified_session_id, 0) { ## Custom Stores -You can easily create your own custom store in order to control how session data is +You can easily create your own custom store in order to control how session data is stored and retrieved. Each session store needs to implement the `Store[T]` interface. ```v ignore @@ -330,6 +341,6 @@ Only the `get`, `destroy` and `set` methods are required to implement. ### Session Expire time -The `max_age` argument in `get` can be used to check whether the session is still valid. +The `max_age` argument in `get` can be used to check whether the session is still valid. The database and memory store both check the expiration time from the time the session data first inserted. But if `max_age = 0`, the stores will not check for expiration time. diff --git a/vlib/x/sessions/sessions.v b/vlib/x/sessions/sessions.v index 934749cb9..95cbd879d 100644 --- a/vlib/x/sessions/sessions.v +++ b/vlib/x/sessions/sessions.v @@ -16,7 +16,7 @@ pub fn new_session_id(secret []u8) (string, string) { hashed := hmac.new(secret, sid.bytes(), sha256.sum, sha256.block_size) - // seperate session id and hmac with a `.` + // separate session id and hmac with a `.` return sid, '${sid}.${base64.url_encode(hashed)}' } @@ -161,7 +161,7 @@ pub fn (mut s Sessions[T]) save[X](mut ctx X, data T) ! { // resave saves `data` for the current session and reset the session id. // You should use this function when the authentication or authorization status changes // e.g. when a user signs in or switches between accounts/permissions. -// This function also destroys the data associtated to the old session id. +// This function also destroys the data associated to the old session id. pub fn (mut s Sessions[T]) resave[X](mut ctx X, data T) ! { if sid := s.get_session_id(ctx) { s.store.destroy(sid)! diff --git a/vlib/x/templating/dtm/README.md b/vlib/x/templating/dtm/README.md index 57f2dd091..f7e2f85ae 100644 --- a/vlib/x/templating/dtm/README.md +++ b/vlib/x/templating/dtm/README.md @@ -7,7 +7,7 @@ templates with Vweb, without the need to recompile the application with every ch Using the dynamic template manager ( named '**dtm**' in this readme) is relatively straightforward. You just need to initialize an instance. Then, call the '**expand**' function in the code that -manages your template. +manages your template. Before starting, You can specify a folder, but it is not mandatory to store the generated cache. If nothing is specified or if there is a problem with the targeted folder (for example, a permission @@ -50,6 +50,7 @@ fn main() { println(render) } ``` + #### and its template text format : ``` @@ -109,17 +110,17 @@ pub fn (mut app App) index(mut ctx Context) vweb.Result { #### and its template html format : -```html - +```html + - - @title - - -
-

@title

-
- + + @title + + +
+

@title

+
+ ``` @@ -140,12 +141,12 @@ Three parameters are available: - `def_cache_path` : ( **String** value ) User can define the path of cache folder. - `max_size_data_in_mem` : ( **Int** value ) Maximum size of data allowed in memory for each cached template. The value must be specified in kilobytes. ( Default is: 500KB / Limit max is : 500KB ) -- `compress_html` : ( **Bool** value ) Light '**minifier**' of the HTML ouput, to remove all +- `compress_html` : ( **Bool** value ) Light '**minifier**' of the HTML output, to remove all unnecessary spacing. ( Default is true, parameter taken into account only for HTML files ) - `active_cache_server` : ( **Bool** value ) Activate or not the template cache system. ( Default is true, ***_Highly recommended to keep it enabled for optimal performance_*** ) -Regarding the `compress_html` option, it is recommended for performance reasons to disable it +Regarding the `compress_html` option, it is recommended for performance reasons to disable it when working directly with raw template generation (i.e., with the cache system disabled). Use it like this : @@ -167,18 +168,21 @@ initialize( - `cache_delay_expiration` ( **i64** value ) Specifies the cache expiration time for the concerned page in seconds. ( Default value is **86400** seconds or one day ). You can add any value you - want in seconds as long as it remains within the indicated range ( see below ). + want in seconds as long as it remains within the indicated range ( see below ). Possibility to use already defined cache delay constants like: + - `cache_delay_expiration_at_min` : five minutes - `cache_delay_expiration_at_max` : one year - `cache_delay_expiration_by_default` : one day For specific cases, you can cancel the generation and use of cache file, even if the cache system is active : + - `cache_delay_expiration` : -1 Or set a cache that will never expire: + - `cache_delay_expiration` : 0 Example : @@ -216,6 +220,7 @@ expand('path/of/template.html', placeholders: &plhs ) ``` + Pay attention to this particular tag: "**_#includehtml**", it enables you to include HTML in the dynamic content. Without this tag, all characters will be escaped for obvious security reasons. By using this tag, only certain HTML tags are allowed. Here is the list: @@ -239,27 +244,27 @@ using this tag, only certain HTML tags are allowed. Here is the list: An example of a template, corresponding to the previous subsection: ```html - + - - @placeholder_name_1 - - -
-

@placeholder_name_1

-

@placeholder_name_2

- @placeholder_name_3 -
- + + @placeholder_name_1 + + +
+

@placeholder_name_1

+

@placeholder_name_2

+ @placeholder_name_3 +
+ ``` + You will note that the `'_#includehtml'` directive is not found in the template with `'@placeholder_name_3'`, and this is entirely normal. Directives are specially handled by the DTM, and including them in the name of your placeholders within the template will result in the placeholder not being found because it does not match the key name defined in the map containing the dynamic content. - Like the traditional template system in V, inclusions or placeholders start with the '**@**' character. The traditional inclusion system is still perfectly usable, such as: @@ -277,4 +282,4 @@ template itself. Able to be used in contexts other than HTML and raw text. This will come in time. -Feel free to report any issues or contribute to the project! \ No newline at end of file +Feel free to report any issues or contribute to the project! diff --git a/vlib/x/templating/dtm/dynamic_template_manager.v b/vlib/x/templating/dtm/dynamic_template_manager.v index ea03e49dc..b40eb66cd 100644 --- a/vlib/x/templating/dtm/dynamic_template_manager.v +++ b/vlib/x/templating/dtm/dynamic_template_manager.v @@ -19,7 +19,7 @@ pub const cache_delay_expiration_at_max = 31536000 pub const cache_delay_expiration_by_default = 86400 // Setting channel capacity of the cache handler. const cache_handler_channel_cap = 200 -// Setting the maximum data size (500 KB) to be stored at memory mode. If this limit is exceeded, cache hander switch to disk mode. +// Setting the maximum data size (500 KB) to be stored at memory mode. If this limit is exceeded, cache handler switch to disk mode. const max_size_data_in_memory = 500 // Defines the maximum character length for placeholder keys. const max_placeholders_key_size = 50 @@ -86,7 +86,7 @@ mut: // Dtm clock c_time i64 ch_stop_dtm_clock chan bool = chan bool{cap: 5} - // Store small informations about already cached pages to improve the verification speed of the check_tmpl_and_placeholders_size function. + // Store small information about already cached pages to improve the verification speed of the check_tmpl_and_placeholders_size function. html_file_info shared map[string]HtmlFileInfo = map[string]HtmlFileInfo{} // Indicates whether the cache file storage directory is located in a temporary OS area cache_folder_is_temporary_storage bool @@ -177,11 +177,11 @@ pub struct DynamicTemplateManagerInitialisationParams { // initialize create and init the 'DynamicTemplateManager' with the storage mode, cache/templates path folders. // A cache directory can be created by the user for storage. If it is not defined or encounters issues such as permission problems, // the DTM will attempt to create it in the OS's temporary area. If this proves impossible, the cache system will be deactivated and the user will be informed if cache system was required. -// Initalisation params are : +// Initialisation params are : // // - def_cache_path 'type string' User can define the path of cache folder. // - max_size_data_in_mem 'type int' Maximum size of data allowed in memory for caching. The value must be specified in kilobytes. ( Default is: 500KB / Limit max is : 500KB) -// - compress_html: 'type bool' Light compress of the HTML ouput. ( default is true ) +// - compress_html: 'type bool' Light compress of the HTML output. ( default is true ) // - active_cache_server: 'type bool' Activate or not the template cache system. ( default is true ) // - test_cache_dir: 'type string' Used only for DTM internal test file, parameter is ignored otherwise. // - test_template_dir: 'type string' Used only for DTM internal test file, parameter is ignored otherwise. @@ -312,7 +312,7 @@ pub fn (mut tm DynamicTemplateManager) expand(tmpl_path string, tmpl_var Templat // Get last modification timestamp of HTML template to adding info for the creation of cache. last_template_mod = os.file_last_mod_unix(file_path) } else { - // Get last modification timestamp of HTML template to compare with cache info already existant. + // Get last modification timestamp of HTML template to compare with cache info already existent. test_current_template_mod = os.file_last_mod_unix(file_path) } @@ -511,7 +511,7 @@ fn (mut tm DynamicTemplateManager) check_tmpl_and_placeholders_size(f_path strin // fn (mut DynamicTemplateManager) create_template_cache_and_display(CacheRequest, i64, i64, string, string, i64, &map[string]DtmMultiTypeMap, string, TemplateType) return string // // Exclusively invoked from `expand`. -// It role is generate the template rendering and relaying informations +// It role is generate the template rendering and relaying information // to the cache manager for either the creation or updating of the template cache. // It begin to starts by ensuring that the cache delay expiration is correctly set by user. // It then parses the template file, replacing placeholders with actual dynamics/statics values. @@ -521,7 +521,7 @@ fn (mut tm DynamicTemplateManager) check_tmpl_and_placeholders_size(f_path strin // The function returns the rendered immediately, without waiting for the cache to be created or updated. // fn (mut tm DynamicTemplateManager) create_template_cache_and_display(tcs CacheRequest, last_template_mod i64, unique_time i64, file_path string, tmpl_name string, cache_delay_expiration i64, placeholders &map[string]DtmMultiTypeMap, current_content_checksum string, tmpl_type TemplateType) string { - // Control if cache delay expiration is correctly setted. See the function itself for more details. + // Control if cache delay expiration is correctly set. See the function itself for more details. check_if_cache_delay_iscorrect(cache_delay_expiration, tmpl_name) or { eprintln(err) return dtm.internat_server_error @@ -586,7 +586,7 @@ fn (tm DynamicTemplateManager) create_temp_cache(html &string, f_path string, ts // Converts the HTML content into a byte array html_bytes := html.bytes() mut f := os.create(cache_path) or { - eprintln('${dtm.message_signature_error} Cannot create tempory cache file : ${err.msg()}') + eprintln('${dtm.message_signature_error} Cannot create temporary cache file : ${err.msg()}') return false, '' } f.write(html_bytes) or { @@ -670,7 +670,7 @@ fn (mut tm DynamicTemplateManager) return_cache_info_isexistent(tmpl_path string goto re_loop } } - // No cache redirection, get cache current informations. + // No cache redirection, get cache current information. } else { // function is used to signal that the process has begun using the cache information. tm.remaining_template_request(true, value.id) @@ -1036,7 +1036,7 @@ fn check_if_cache_delay_iscorrect(cde i64, tmpl_name string) ! { // fn (mut tm DynamicTemplateManager) cache_request_route(is_cache_exist bool, neg_cache_delay_expiration i64, last_template_mod i64, test_current_template_mod i64, cache_del_exp i64, gen_at i64, c_time i64, content_checksum string, current_content_checksum string) (CacheRequest, i64) { if !is_cache_exist || neg_cache_delay_expiration == -1 { - // Requiere cache creation + // Require cache creation unique_ts := get_current_unix_micro_timestamp() tm.c_time = unique_ts return CacheRequest.new, unique_ts diff --git a/vlib/x/templating/dtm/dynamic_template_manager_cache_system_test.v b/vlib/x/templating/dtm/dynamic_template_manager_cache_system_test.v index d6dbabfb6..19a21698f 100644 --- a/vlib/x/templating/dtm/dynamic_template_manager_cache_system_test.v +++ b/vlib/x/templating/dtm/dynamic_template_manager_cache_system_test.v @@ -62,9 +62,9 @@ fn test_get_cache() { dtmi.stop_cache_handler() } if !dtmi.abort_test { - dtm_placeholers := map[string]DtmMultiTypeMap{} + dtm_placeholders := map[string]DtmMultiTypeMap{} temp_html_file := os.join_path(dtmi.template_folder, dtm.temp_html_fp) - html_mem := dtmi.get_cache(dtm.temp_html_n, temp_html_file, &dtm_placeholers) + html_mem := dtmi.get_cache(dtm.temp_html_n, temp_html_file, &dtm_placeholders) assert html_mem.len > 10 } } diff --git a/vlib/x/vweb/README.md b/vlib/x/vweb/README.md index cf0ed3dee..3f143d92e 100644 --- a/vlib/x/vweb/README.md +++ b/vlib/x/vweb/README.md @@ -32,6 +32,7 @@ represent your app and a structure which will represent the context of a request These structures must be declared with the `pub` keyword. **Example:** + ```v module main @@ -87,6 +88,7 @@ For routing you can either use auto-mapping of function names or specify the pat The function expects a parameter of your Context type and a response of the type `vweb.Result`. **Example:** + ```v ignore // This endpoint can be accessed via http://server:port/hello pub fn (app &App) hello(mut ctx Context) vweb.Result { @@ -182,7 +184,7 @@ If we visit http://localhost:port/hello/vaesel we would see the text `Hello vaes ### Routes with Parameter Arrays If you want multiple parameters in your route and if you want to parse the parameters -yourself, or you want a wildcard route, you can add `...` after the `:` and name, +yourself, or you want a wildcard route, you can add `...` after the `:` and name, e.g. `@['/:path...']`. This will match all routes after `'/'`. For example, the url `/path/to/test` would give @@ -207,6 +209,7 @@ will see the text `Hello vweb!`. And if we access the route without the `name` p http://localhost:port/user, we will see the text `no user was found`, **Example:** + ```v ignore @['/user'; get] pub fn (app &App) get_user_by_id(mut ctx Context) vweb.Result { @@ -220,6 +223,7 @@ pub fn (app &App) get_user_by_id(mut ctx Context) vweb.Result { ``` ### Host + To restrict an endpoint to a specific host, you can use the `host` attribute followed by a colon `:` and the host name. You can test the Host feature locally by adding a host to the "hosts" file of your device. @@ -252,6 +256,7 @@ host in one app struct. vweb will match routes in the order that you define endpoints. **Example:** + ```v ignore @['/:path'] pub fn (app &App) with_parameter(mut ctx Context, path string) vweb.Result { @@ -276,7 +281,7 @@ has to be defined on our Context struct. **Example:** -``` v ignore +```v ignore pub fn (mut ctx Context) not_found() vweb.Result { // set HTTP status 404 ctx.res.set_status(.not_found) @@ -293,6 +298,7 @@ of our web app, or at a custom route. To start using static files we have to emb **Example:** Let's say you have the following file structure: + ``` . ├── static/ @@ -310,7 +316,8 @@ use `handle_static`. > vweb will recursively search the folder you mount; all the files inside that folder > will be publicly available. -*main.v* +_main.v_ + ```v module main @@ -343,10 +350,12 @@ to mount the static folder at the root of our app: everything inside the `static is available at `/`. **Example:** + ```v ignore // change the second argument to `true` to mount a folder at the app root app.handle_static('static', true)! ``` + We can now access `main.css` directly at http://localhost:8080/css/main.css. If a request is made to the root of a static folder, vweb will look for an @@ -357,6 +366,7 @@ An example is available [here](/examples/vweb/static_website). It is also possible to mount the `static` folder at a custom path. **Example:** + ```v ignore // mount the folder 'static' at path '/public', the path has to start with '/' app.mount_static_folder_at('static', '/public') @@ -369,6 +379,7 @@ If we run our app the `main.css` file is available at http://localhost:8080/publ If you don't want to mount an entire folder, but only a single file, you can use `serve_static`. **Example:** + ```v ignore // serve the `main.css` file at '/path/main.css' app.serve_static('/path/main.css', 'static/css/main.css')! @@ -383,26 +394,31 @@ have to add your MIME type to `.static_mime_types` yourself. **Example:** Let's say you have the following file structure: + ``` . ├── static/ │ └── file.what └── main.v ``` + ```v ignore app.handle_static('static', true)! ``` + This code will throw an error, because vweb has no default MIME type for a `.what` file extension. + ``` -unkown MIME type for file extension ".what" +unknown MIME type for file extension ".what" ``` + To fix this we have to provide a MIME type for the `.what` file extension: + ```v ignore app.static_mime_types['.what'] = 'txt/plain' app.handle_static('static', true)! ``` - ## Middleware Middleware in web development is (loosely defined) a hidden layer that sits between @@ -413,6 +429,7 @@ To use vweb's middleware we have to embed `vweb.Middleware` on our app struct an the type of which context struct should be used. **Example:** + ```v ignore pub struct App { vweb.Middleware[Context] @@ -426,6 +443,7 @@ accepted our cookie policy. Let's modify our Context struct to store whether the accepted our policy or not. **Example:** + ```v ignore pub struct Context { vweb.Context @@ -441,6 +459,7 @@ The return value indicates to vweb whether it can continue or has to stop. If we response to the client in a middleware function vweb has to stop, so we return `false`. **Example:** + ```v ignore pub fn check_cookie_policy(mut ctx Context) bool { // get the cookie @@ -457,6 +476,7 @@ pub fn check_cookie_policy(mut ctx Context) bool { We can check this value in an endpoint and return a different response. **Example:** + ```v ignore @['/only-cookies'] pub fn (app &App) only_cookie_route(mut ctx Context) vweb.Result { @@ -473,6 +493,7 @@ function as middleware for our app. We must do this after the app is created and app is started. **Example:** + ```v ignore fn main() { mut app := &App{} @@ -492,6 +513,7 @@ applies to every endpoint defined on our app struct; global. It is also possible to register middleware for only a certain route(s). **Example:** + ```v ignore // register middleware only for the route '/auth' app.route_use('/auth', handler: auth_middleware) @@ -510,6 +532,7 @@ app struct is called. You can also change this behaviour to execute middleware f *after* a method on your app struct is called, but before the response is sent! **Example:** + ```v ignore pub fn modify_headers(mut ctx Context) bool { // add Content-Language: 'en-US' header to each response @@ -517,6 +540,7 @@ pub fn modify_headers(mut ctx Context) bool { return true } ``` + ```v ignore app.use(handler: modify_headers, after: true) ``` @@ -547,6 +571,7 @@ If any middleware sends a response (and thus must return `false`) vweb will not other middleware, or the endpoint method, and immediately send the response. **Example:** + ```v ignore pub fn early_exit(mut ctx Context) bool { ctx.text('early exit') @@ -559,6 +584,7 @@ pub fn logger(mut ctx Context) bool { return true } ``` + ```v ignore app.use(handler: early_exit) app.use(handler: logger) @@ -569,7 +595,7 @@ Because we register `early_exit` before `logger` our logging middleware will nev ## Controllers Controllers can be used to split up your app logic so you are able to have one struct -per "route group". E.g. a struct `Admin` for urls starting with `'/admin'` and a struct `Foo` +per "route group". E.g. a struct `Admin` for urls starting with `'/admin'` and a struct `Foo` for urls starting with `'/foo'`. To use controllers we have to embed `vweb.Controller` on @@ -578,6 +604,7 @@ what the type of the context struct will be. That means that it is possible to have a different context struct for each controller and the main app struct. **Example:** + ```v module main @@ -637,6 +664,7 @@ pub fn (app &Admin) path(mut ctx Context) vweb.Result { return ctx.text('Admin') } ``` + When we registered the controller with `app.register_controller[Admin, Context]('/admin', mut admin_app)!` we told vweb that the namespace of that controller is `'/admin'` so in this example we would @@ -651,6 +679,7 @@ pub fn (app &App) admin_path(mut ctx Context) vweb.Result { return ctx.text('Admin overwrite') } ``` + There will be an error, because the controller `Admin` handles all routes starting with `'/admin'`: the endpoint `admin_path` is unreachable. @@ -660,6 +689,7 @@ You can also set a host for a controller. All requests coming to that host will by the controller. **Example:** + ```v ignore struct Example {} @@ -668,6 +698,7 @@ pub fn (app &Example) index(mut ctx Context) vweb.Result { return ctx.text('Example') } ``` + ```v ignore mut example_app := &Example{} // set the controllers hostname to 'example.com' and handle all routes starting with '/', @@ -689,6 +720,7 @@ You can directly access the HTTP request on the `.req` field. #### Get request headers **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { content_length := ctx.get_header(.content_length) or { '0' } @@ -701,6 +733,7 @@ pub fn (app &App) index(mut ctx Context) vweb.Result { #### Get a cookie **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { cookie_val := ctx.get_cookie('token') or { '' } @@ -730,6 +763,7 @@ ctx.json(User{ #### Sending files **Example:** + ```v ignore pub fn (app &App) file_response(mut ctx Context) vweb.Result { // send the file 'image.png' in folder 'data' to the user @@ -740,6 +774,7 @@ pub fn (app &App) file_response(mut ctx Context) vweb.Result { #### Set response headers **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { ctx.set_header(.accept, 'text/html') @@ -752,6 +787,7 @@ pub fn (app &App) index(mut ctx Context) vweb.Result { #### Set a cookie **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { ctx.set_cookie(http.Cookie{ @@ -768,6 +804,7 @@ pub fn (app &App) index(mut ctx Context) vweb.Result { #### Redirect You must pass the type of redirect to vweb: + - `moved_permanently` HTTP code 301 - `found` HTTP code 302 - `see_other` HTTP code 303 @@ -781,6 +818,7 @@ want to redirect to another page via a GET request, you should use `see_other`. the HTTP method to stay the same, you should use `found` generally speaking. **Example:** + ```v ignore pub fn (app &App) index(mut ctx Context) vweb.Result { token := ctx.get_cookie('token') or { '' } @@ -797,6 +835,7 @@ pub fn (app &App) index(mut ctx Context) vweb.Result { #### Sending error responses **Example:** + ```v ignore pub fn (app &App) login(mut ctx Context) vweb.Result { if username := ctx.form['username'] { @@ -831,6 +870,7 @@ and returns an empty `vweb.Result` struct, letting vweb know that we sent a resp > It is important to call `ctx.takeover_conn` before you spawn a thread **Example:** + ```v module main diff --git a/vlib/x/vweb/assets/README.md b/vlib/x/vweb/assets/README.md index 33e431c10..2dc655311 100644 --- a/vlib/x/vweb/assets/README.md +++ b/vlib/x/vweb/assets/README.md @@ -1,13 +1,14 @@ # Assets -The asset manager for vweb. You can use this asset manager to minify CSS and Javscript files, +The asset manager for vweb. You can use this asset manager to minify CSS and JavaScript files, combine them into a single file and to make sure the asset you're using exists. ## Usage -Add `AssetManager` to your App struct to use the asset manager. +Add `AssetManager` to your App struct to use the asset manager. **Example:** + ```v module main @@ -35,12 +36,15 @@ If you want to include an asset in your templates you can use the `include` meth First pass the type of asset (css or js), then specify the "include name" of an asset. **Example:** + ```html @{app.am.include(.css, 'main.css')} ``` + Will generate + ```html - + ``` ### Adding assets @@ -49,6 +53,7 @@ To add an asset use the `add` method. You must specify the path of the asset and include name will be: the name that you will use in templates. **Example:** + ```v ignore // add a css file at the path "css/main.css" and set its include name to "main.css" app.am.add(.css, 'css/main.css', 'main.css') @@ -60,6 +65,7 @@ If you want to minify each asset you must set the `minify` field and specify the folder. Each assest you add is minifed and outputted in `cache_dir`. **Example:** + ```v ignore pub struct App { pub mut: @@ -74,6 +80,7 @@ To combine the all currently added assets into a single file you must call the ` and specify which asset type you want to combine. **Example:** + ```v ignore // `combine` returns the path of the minified file minified_file := app.am.combine(.css)! @@ -81,10 +88,11 @@ minified_file := app.am.combine(.css)! ### Handle folders -You can use the asset manger in combination with vweb's `StaticHandler` to serve +You can use the asset manger in combination with vweb's `StaticHandler` to serve assets in a folder as static assets. **Example:** + ```v ignore pub struct App { vweb.StaticHandler @@ -92,7 +100,9 @@ pub mut: am assets.AssetManager } ``` + Let's say we have the following folder structure: + ``` assets/ ├── css/ @@ -104,6 +114,7 @@ assets/ We can tell the asset manager to add all assets in the `static` folder **Example:** + ```v ignore fn main() { mut app := &App{} @@ -116,17 +127,18 @@ fn main() { } ``` -The include name of each minified asset will be set to its relative path, -so if you want to include `main.css` in your template you would write +The include name of each minified asset will be set to its relative path, +so if you want to include `main.css` in your template you would write `@{app.am.include('css/main.css')}` #### Minify -If you add an asset folder and want to minify those assets you can call the +If you add an asset folder and want to minify those assets you can call the `cleanup_cache` method to remove old files from the cache folder that are no longer needed. **Example:** + ```v ignore pub struct App { vweb.StaticHandler @@ -155,6 +167,7 @@ fn main() { You can add a custom prefix to the include name of assets when adding a folder. **Example:** + ```v ignore // add all assets in the "assets" folder app.am.handle_assets_at('assets', 'static')! diff --git a/vlib/x/vweb/context.v b/vlib/x/vweb/context.v index 7f463e400..6f0a9b389 100644 --- a/vlib/x/vweb/context.v +++ b/vlib/x/vweb/context.v @@ -23,7 +23,7 @@ pub enum RedirectType { @[heap] pub struct Context { mut: - // vweb wil try to infer the content type base on file extension, + // vweb will try to infer the content type base on file extension, // and if `content_type` is not empty the `Content-Type` header will always be // set to this value content_type string @@ -277,8 +277,8 @@ pub fn (mut ctx Context) set_content_type(mime string) { // takeover_conn prevents vweb from automatically sending a response and closing // the connection. You are responsible for closing the connection. // In takeover mode if you call a Context method the response will be directly -// send over the connetion and you can send multiple responses. -// This function is usefull when you want to keep the connection alive and/or +// send over the connection and you can send multiple responses. +// This function is useful when you want to keep the connection alive and/or // send multiple responses. Like with the SSE. pub fn (mut ctx Context) takeover_conn() { ctx.takeover = true diff --git a/vlib/x/vweb/static_handler.v b/vlib/x/vweb/static_handler.v index c03ff2fae..ac28d2b9f 100644 --- a/vlib/x/vweb/static_handler.v +++ b/vlib/x/vweb/static_handler.v @@ -108,7 +108,7 @@ pub fn (mut sh StaticHandler) host_serve_static(host string, url string, file_pa // Rudimentary guard against adding files not in mime_types. if ext !in sh.static_mime_types && ext !in mime_types { - return error('unkown MIME type for file extension "${ext}". You can register your MIME type in `app.static_mime_types`') + return error('unknown MIME type for file extension "${ext}". You can register your MIME type in `app.static_mime_types`') } sh.static_files[url] = file_path sh.static_hosts[url] = host diff --git a/vlib/x/vweb/tests/large_payload_test.v b/vlib/x/vweb/tests/large_payload_test.v index 8989b3cad..7c5822b9a 100644 --- a/vlib/x/vweb/tests/large_payload_test.v +++ b/vlib/x/vweb/tests/large_payload_test.v @@ -67,7 +67,7 @@ fn test_large_request_body() { fn test_large_request_header() { // same test as test_large_request_body, but then with a large header, - // which is parsed seperately + // which is parsed separately mut buf := []u8{len: vweb.max_read * 2, init: `a`} str := buf.bytestr() diff --git a/vlib/x/vweb/tests/static_handler_test.v b/vlib/x/vweb/tests/static_handler_test.v index 365dcf661..61c7cb056 100644 --- a/vlib/x/vweb/tests/static_handler_test.v +++ b/vlib/x/vweb/tests/static_handler_test.v @@ -46,9 +46,9 @@ fn testsuite_begin() { fn run_app_test() { mut app := &App{} if _ := app.handle_static('testdata', true) { - assert true == false, 'should throw unkown mime type error' + assert true == false, 'should throw unknown mime type error' } else { - assert err.msg().starts_with('unkown MIME type for file extension ".what"'), 'throws error on unkown mime type' + assert err.msg().starts_with('unknown MIME type for file extension ".what"'), 'throws error on unkown mime type' } app.static_mime_types['.what'] = vweb.mime_types['.txt'] @@ -106,11 +106,11 @@ fn test_index_subdirs() { } fn test_custom_mime_types() { - x := http.get('${localserver}/unkown_mime.what')! + x := http.get('${localserver}/unknown_mime.what')! assert x.status() == .ok assert x.header.get(.content_type)! == vweb.mime_types['.txt'] - assert x.body == 'unkown_mime' + assert x.body.trim_space() == 'unknown_mime' } fn test_custom_folder_mount() { diff --git a/vlib/x/vweb/tests/testdata/unknown_mime.what b/vlib/x/vweb/tests/testdata/unknown_mime.what new file mode 100644 index 000000000..00267a3e7 --- /dev/null +++ b/vlib/x/vweb/tests/testdata/unknown_mime.what @@ -0,0 +1 @@ +unknown_mime diff --git a/vlib/x/vweb/tests/testdata/unkown_mime.what b/vlib/x/vweb/tests/testdata/unkown_mime.what deleted file mode 100644 index b04592d50..000000000 --- a/vlib/x/vweb/tests/testdata/unkown_mime.what +++ /dev/null @@ -1 +0,0 @@ -unkown_mime \ No newline at end of file diff --git a/vlib/x/vweb/vweb.v b/vlib/x/vweb/vweb.v index 09b520f35..0094158a9 100644 --- a/vlib/x/vweb/vweb.v +++ b/vlib/x/vweb/vweb.v @@ -466,7 +466,7 @@ fn handle_write_string(mut pv picoev.Picoev, mut params RequestParams, fd int) { // handle_read reads data from the connection and if the request is complete // it calls `handle_route` and closes the connection. // If the request is not complete it stores the incomplete request in `params` -// and the conenction stays open until it is ready to read again +// and the connection stays open until it is ready to read again @[direct_array_access; manualfree] fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) { mut conn := &net.TcpConn{ @@ -486,7 +486,7 @@ fn handle_read[A, X](mut pv picoev.Picoev, mut params RequestParams, fd int) { // take the previous incomplete request mut req := params.incomplete_requests[fd] - // check if there is an incomplete request for this file desriptor + // check if there is an incomplete request for this file descriptor if params.idx[fd] == 0 { // set the read and write timeout according to picoev settings when the // connection is first encountered @@ -900,7 +900,7 @@ fn route_matches(url_words []string, route_words []string) ?[]string { if url_words.len == route_words.len { for i in 0 .. url_words.len { if route_words[i].starts_with(':') { - // We found a path paramater + // We found a path parameter params << url_words[i] } else if route_words[i] != url_words[i] { // This url does not match the route @@ -917,7 +917,7 @@ fn route_matches(url_words []string, route_words []string) ?[]string { for i in 0 .. route_words.len - 1 { if route_words[i].starts_with(':') { - // We found a path paramater + // We found a path parameter params << url_words[i] } else if route_words[i] != url_words[i] { // This url does not match the route -- 2.39.5