diff options
Diffstat (limited to '_doc')
| -rw-r--r-- | _doc/CHANGELOG_2024.adoc | 868 | ||||
| -rw-r--r-- | _doc/index.adoc | 3 |
2 files changed, 871 insertions, 0 deletions
diff --git a/_doc/CHANGELOG_2024.adoc b/_doc/CHANGELOG_2024.adoc new file mode 100644 index 00000000..cc9a4256 --- /dev/null +++ b/_doc/CHANGELOG_2024.adoc @@ -0,0 +1,868 @@ += pakakeh.go CHANGELOG +:toc: +:sectanchors: + +This library is released every month, usually at the first week of month. + +link:CHANGELOG_2023.html[Changelog in 2023^]. +This is changelog for `pakakeh.go` module since v0.43.0 until v0.51.0. + +link:CHANGELOG_2022.html[Changelog in 2022^]. +This is changelog for `pakakeh.go` module since v0.33.0 until v0.42.0. + +link:CHANGELOG_2021.html[Changelog in 2021^]. +This is changelog for `pakakeh.go` module since v0.22.0 until v0.32.0. + +link:CHANGELOG_2020.html[Changelog in 2020^]. +This is changelog for `pakakeh.go` module since v0.12.0 until v0.21.0. + +link:CHANGELOG_2018-2019.html[Changelog from 2018 to 2019^]. +This is changelog for `pakakeh.go` module since v0.1.0 until v0.11.0. + + +[#v0_58_1] +== pakakeh.go v0.58.1 (2024-12-07) + +[#v0_58_1__enhancements] +=== Enhancements + +lib/play: add custom request to run unsafe directory directly:: ++ +-- +As exceptional, the Run and HTTPHandleRun accept the following +request for running program inside custom "go.mod", + +---- +{ + "unsafe_run": <path> +} +---- + +The "unsafe_run" define the path to directory relative to HTTP +server working directory. +Once request accepted it will change the directory into +"unsafe_run" first and then run "go run ." directly. +Go code that executed inside "unsafe_run" should be not +modifiable and safe from mallicious execution. +-- + + +lib/play: add option to Run with specific Go version and without race:: ++ +The idea is to allow testing Go code on specific Go version. +For example, before Go 1.22, the for loop with variable is shared +among block statements, which cause every use of that variable is run +with the last value. + + +lib/play: expose the Timeout variable:: ++ +By exposing the Timeout, user can set their maximum time the program +can run in their playground. + + +[#v0_58_0] +== pakakeh.go v0.58.0 (2024-10-06) + +This release update the minimum Go module to 1.22.0, the last version +supported by Go tools. + +[#v0_58_0__breaking_changes] +=== Breaking changes + +lib/http: remove writing StatusNoContent on ResponseTypeNode:: ++ +To make it consistent with RequestTypeNone, the +ResponseTypeNone should not write any response header or +HTTP status code. +It will be handled manually by [Endpoint.Call]. + +[#v0_58_0__new_features] +=== New features + +lib/play: new package for formatting and running Go code:: ++ +Package play provides callable APIs and HTTP handlers to format and +run Go code, similar to Go playground, but using HTTP instead of +WebSocket. + +lib/http: add Server method to register handler by function:: ++ +-- +The RegisterHandleFunc register a pattern with a handler, similar to +[http.ServeMux.HandleFunc]. +The pattern follow the Go 1.22 format: + + [METHOD] PATH + +The METHOD is optional, default to GET. +The PATH must not contains the domain name and space. +Unlike standard library, variable in PATH is read using ":var" not +"{var}". +This endpoint will accept any content type and return the body as is; +it is up to the handler to read and set the content type and the +response headers. + +If the METHOD and/or PATH is already registered it will panic. +-- + + +lib/bytes: add function AppendInt64 and AppendUint64:: ++ +The AppendInt64 append an int64 value into slice of byte. +The AppendUint64 append an uint64 value into slice of byte. + + +[#v0_57_0] +== pakakeh.go v0.57.0 (2024-09-03) + +[#v0_57_0__breaking_changes] +=== Breaking changes + +lib/sql: replace [http.FileSystem] with [memfs.MemFS]:: ++ +-- +Accepting the [http.FileSystem] means that the parameter can receive an +instance of [embed.FS], but in most cases, it will fail. + +Case example, when we embed SQL files for migration under +"db/migration" using the "go:embed" directive, + + //go:embed db/migration/*.sql + var DBMigrationFS embed.FS + +and then call the [Migrate] function, it will not find any ".sql" +files inside the "/" directory because the files is stored under +"db/migration/" prefix (also there is no "/" when using embed.FS). +-- + +[#v0_57_0__chores] +=== Chores + +lib/memfs: document the comparison with "go:embed" directive:: ++ +-- +Compare it to "go:embed", the memfs package is more flexible and +portable. +Currently, we found three disadvantages of using "go:embed", + +- The "go:embed" only works if files or directory to be + embedded is in the same parent directory. +- Accessing the embedded file require the original path. +- No development mode. + +None of those limitation affected the memfs package. +-- + + +[#v0_56_0] +== pakakeh.go v0.56.0 (2024-08-04) + +[#v0_56_0__new_features] +=== New features + +cmd/emaildecode: CLI to decode email body to plain text:: ++ +The emaildecode accept file as input. +If the email header contains content-transfer-encoding with value +quoted-printable or base64, it will decode the message body and print it +to stdout as plain text. + +[#v0_56_0__bug_fixes] +=== Bug fixes + +lib/memfs: another fix for refresh:: ++ +In previous commit we use wrong condition when handling directory "." as +Root. + +[#v0_56_0__enhancements] +=== Enhancements + +lib/email: allow message that end lines with LF only:: ++ +Although, a message from network must end with CRLF, a message from +(another) client may have been sanitized and end with LF only. + +lib/email: decode the message body based on content-transfer-encoding:: ++ +After the header and body has been parsed, if the header contains +Content-Transfer-Encoding, we decode the body into its local formats. +Currently supported encoding is "quoted-printable" and "base64". + +[#v0_56_0__others] +=== Others + +lib/email: export the Header fields:: ++ +By exporting the fields, this allow the caller to filter or manage the +field manually. + +_doc: add partial note and summary for RFC 2183:: ++ +The RFC 2183 is define Content-Disposition header field in the internet +message. + +lib/ini: mention that marshaling []byte does not supported:: ++ +Due to "byte" is considered as "uint8" during reflection, we cannot tell +whether the value is slice of byte of slice of number with type uint8. + + +[#v0_55_2] +== pakakeh.go v0.55.2 (2024-07-22) + +[#v0_55_2__bug_fix] +=== Bug fix + +lib/memfs: sanitize the Root directory to fix refresh:: ++ +In [MemFS.refresh], if the requested url is "/file1" and [Options.Root] +is ".", the path during refresh become "file1" and if passed to +[filepath.Dir] it will return ".". +This cause the loop on refresh never end because there is no PathNodes +equal with ".". + + +[#v0_55_1] +== pakakeh.go v0.55.1 (2024-06-20) + +[#v0_55_1__enhancements] +=== Enhancements + +lib/http: add request type HTML:: ++ +The RequestTypeHTML define the content type "text/html". + +lib/path: add method Path to Route:: ++ +Unlike String method that may return the key's name in returned path, +the Path method return the path with all the keys has been substituted +with values, even if its empty. + + +[#v0_55_0] +== pakakeh.go v0.55.0 (2024-05-04) + +[#v_55_0__breaking_changes] +=== Breaking changes + +lib/http: refactoring "multipart/form-data" parameters in ClientRequest:: ++ +-- +Previously, ClientRequest with type RequestTypeMultipartForm pass the +type "map[string][]byte" in Params. +This type hold the file upload, where key is the file name and []byte is +content of file. +Unfortunately, this model does not correct because a +"multipart/form-data" can contains different field name and file name, +for example + +---- +--boundary +Content-Disposition: form-data; name="field0"; filename="file0" +Content-Type: application/octet-stream + +<Content of file0> +---- + +This changes fix this by changing the parameter type for +RequestTypeMultipartForm to [*multipart.Form], which affect several +functions including [Client.PutFormData] and [GenerateFormData]. +-- + +[#v0_55_0__bug_fixes] +=== Bug fixes + +lib/dns: fix packing and unpacking OPT record:: ++ +The RDATA in OPT records can contains zero or _more_ options. +Previously, we only handle unpacking and packing one option, now we +handle multiple options. + +telegram/bot: fix Webhook URL registration:: ++ +Using [path.Join] cause "https://domain" become "https:/domain" which +is not a valid URL. +This bug caused by refactoring in b89afa24f. + + +[#v0_55_0__enhancements] +=== Enhancements + +lib/memfs: set embed file mode to print as octal:: ++ +Using octal in mode make the embedded code more readable, for example mode +with permission "0o644" much more readable than 420". + +telegram/bot: register GET endpoint to test webhook:: ++ +-- +The call to get "GET <Webhook.URL.Path>/<Token>" will return HTTP status +200 with JSON body '{"code":200,"message":"OK"}'. + +This endpoint is to check if the bot server is really running. +-- + +lib/http: allow all HTTP method to generate HTTP request with body:: ++ +Although the RFC 7231 says that no special defined meaning for a +payload in GET, some implementation of HTTP API sometimes use GET with +content type "application/x-www-form-urlencoded". + +lib/http: add new function [CreateMultipartFileHeader]:: ++ +The CreateMultipartFileHeader help creating [multipart.FileHeader] +from raw bytes, that can be assigned to [*multipart.Form]. + + +[#v0_54_0] +== pakakeh.go v0.54.0 (2024-04-04) + +This is the first release after we move the repository to SourceHut under +different name: "pakakeh.go". +There are several reasons for moving and naming. + +First, related to the name of package. +We accidentally name the package with "share" a common word in English +that does not reflect the content of repository. +By moving to other repository, we can rename it to better and unique +name, in this "pakakeh.go". +Pakakeh is Minang word for tools, and ".go" suffix indicate that the +repository related to Go programming language. + +Second, supporting open source. +The new repository is hosted under sourcehut.org, the founder is known +to support open source, and all their services are licensed under AGPL, +unlike GitHub that are closed sources. + +Third, regarding GitHub CoPilot. +https://docs.github.com/en/site-policy/github-terms/github-terms-of-service#4-license-grant-to-us[The +GitHub Terms of Service], +allow any public content that are hosted there granted them to parse the +content. +On one side, GitHub helps and flourish the open source, but on another +side have an issues +https://githubcopilotinvestigation.com[issues] +regarding scraping the copyleft license. + + +[#v0_54_0__breaking_changes] +=== Breaking changes + +Since we are moving to new repository, we fix all linter warnings and +inconsistencies that we cannot changes on previous module. + +Breaking changes related to naming, + +* api/slack: [Message.IconUrl] become [Message.IconURL] +* lib/dns: DefaultSoaMinumumTtl become DefaultSoaMinimumTTL +* lib/email: [Message.SetBodyHtml] become [Message.SetBodyHTML] +* lib/http: [Client.GenerateHttpRequest] become + [Client.GenerateHTTPRequest] +* lib/http: [ClientOptions.ServerUrl] become [ClientOptions.ServerURL] +* lib/http: [EndpointRequest.HttpWriter] become + [EndpointRequest.HTTPWriter] +* lib/http: [EndpointRequest.HttpRequest] become + [EndpointRequest.HTTPRequest] +* lib/http: [ServerOptions.EnableIndexHtml] become + [ServerOptions.EnableIndexHTML] +* lib/http: [SSEConn.HttpRequest] become [SSEConn.HTTPRequest] +* lib/smtp: [ClientOptions.ServerUrl] become [ClientOptions.ServerURL] +* lib/ssh/sftp: [FileAttrs.SetUid] become [FileAttrs.SetUID] +* lib/ssh/sftp: [FileAttrs.Uid] become [FileAttrs.UID] + +Changes on packages, + +lib/sql: remove deprecated Row type:: ++ +The Row type has been replaced with Meta type with more flexibility +and features for generating type-safe SQL DML. + +lib/memfs: remove deprecated Merge function:: ++ +The Merge function has been replaced with [memfs.MemFS.Merge] for +better API. + +lib: move package "net/html" to "lib/html":: ++ +Putting "html" under "net" package make no sense. +Another reason is to make the package flat under "lib/" directory. + +lib: move package "ssh/config" to "lib/sshconfig":: ++ +Previously the "ssh/config" is used by the parent package "ssh" and +"ssh/sftp" which is break the rule of package layer (the top package +should be imported by sub package, not the other way around). + +lib/http: refactor of RegisterEndpoint and RegisterSSE to non-pointer:: ++ +Once the endpoint registered, the caller should not able to changes +any values on endpoint again. + +lib/http: refactoring NewServer and NewClient:: ++ +The NewServer and NewClient now accept non-pointer options, so the +caller unable to modify the options once the server or client has +been created. + +lib/http: refactor Client methods to use struct ClientRequest:: ++ +Instead of three parameters, the Client methods now accept single struct +[ClientRequest]. + +lib/http: refactoring Client methods to return struct ClientResponse:: ++ +Instead of returning three variables, [http.Response], []byte, and error, +we combine the [http.Response] and []byte into single struct: +ClientResponse. + +lib/http: refactoring type of RequestMethod from int to string:: ++ +The reason is to make storing or encoding the RequestMethod value readable +from user point of view instead of number, 0, 1, 2, etc. + +lib/http: refactor type of RequestType from int to string:: ++ +The reason is to make storing or encoding the RequestType value readable +from human point of view instead of number, 0, 1, 2, etc. + +lib/http: refactoring type of ResponseType from int to string:: ++ +The reason is to make storing or encoding the value readable +from human point of view instead of number, 0, 1, 2, etc. + +lib/http: refactoring FSHandler type to return [*memfs.Node]:: ++ +-- +Changing FSHandler type to return [*memfs.Node], allow the handler to +redirect or return custom node. + +One of the use case is when service Single Page Application (SPA), where +route is handled by JavaScript. + +For example, when user requested "/dashboard" but dashboard directory +does not exist, one can write the following handler to return +"/index.html", + + node, _ = memfs.Get(`/index.html`) + return node +-- + +lib/dns: refactor [Message.Unpack] to [UnpackMessage]:: ++ +-- +The previous API for Message is a little bit weird. +Its provides creating Message manually, but expose the method +[UnpackHeaderQuestion], meanwhile the field packet itself is unexported. + +In order to make it more clear we refactor [Message.Unpack] to +function [UnpackMessage] that accept raw DNS packet. +-- + + +[#v0_54_0__new_features] +=== New features + +test/httptest: new helper for testing HTTP server handler:: ++ +-- +The Simulate function simulate HTTP server handler by generating +[http.Request] from fields in [SimulateRequest]; and then call +[http.HandlerFunc]. + +The HTTP response from serve along with its raw body and original HTTP +request then returned in [*SimulateResult]. +-- + +lib/dns: implements RFC 9460 for SVCB RR and HTTPS RR:: ++ +The dns package now support packing and unpacking DNS with record type 64 +(SVCB) and 65 (HTTPS). + +cmd/ansua: command line interface to help tracking time:: ++ +-- +Usage, + + ansua <duration> [ "<command>" ] + +ansua execute a timer on defined duration and optionally run a command +when timer finished. + +When ansua timer is running, one can pause the timer by pressing p+Enter, +and resume it by pressing r+Enter, or stopping it using CTRL+c. +-- + + +[#v0_54_0__bug_fixes] +=== Bug fixes + +lib/memfs: trim trailing slash ("/") in the path of Get method:: ++ +The MemFS always store directory without slash. +If caller request a directory node with slash, it will always return nil. + +lib/dns: use ParseUint to parse escaped octet in "\NNN" format:: ++ +Previously, we use ParseInt to parse escaped octet "\NNN", but using +this method only allow decimal from 0 to 127, while the specification +allow 0 to 255. + + +[#v0_54_0__enhancements] +=== Enhancements + +lib/http: handle CORS independently:: ++ +-- +Previously, if [CORSOptions.AllowOrigins] not found we return it +immediately without checking request "Access-Control-Request-Method", +"Access-Control-Request-Headers", and other CORS options. + +This changes check each of them, a missing allow origins does not +means empty allowed method, headers, MaxAge, or credentials. +-- + +lib/bytes: add parameter networkByteOrder to ParseHexDump:: ++ +-- +If networkByteOrder is true, the ParseHexDump read each hex string +in network byte order or as order defined in text. + +While at it, fix reading and parsing single byte hex. +-- + +cmd/httpdfs: set default include options to empty:: ++ +By default httpdfs now serve all files under base directory. + + + +[#v0_53_1] +== pakakeh.go v0.53.1 (2024-03-02) + +[#v0_53_1__enhancements] +=== Enhancements + +lib/sql: handle binding with the same name:: ++ +If [Meta.Bind] is called with the same name again, it should replace +the existing named value. + + +lib/dns: ignore invalid message:: ++ +-- +If Query return a message but the failed to unpack due to invalid +format, for example + + unpackOPT: data length is out of range + +ignore it instead of disconnect the client connection. +-- + + +lib/http: export function to generate "multipart/form-data":: ++ +The GenerateFormData generate the request body with boundary for +HTTP content-type "multipart/form-data" from map[string][]byte. + + +lib/dns: change the log mechanism by mode instead of by level:: ++ +-- +This changes introduce three mode of debug: + +* DebugLevelDNS: log error on DNS level, in example empty answer, + ERR_NAME (domain name is invalid or not known) and so on. + +* DebugLevelCache: log cache operations. + +* DebugLevelConnPacket: log low level connection and package, + including request and response. +-- + + +[#v0_53_0] +== pakakeh.go v0.53.0 (2024-02-04) + +[#v0_53_0__new_features] +=== New features + +test/mock: implement mock for crypto [rand.Reader]:: ++ +-- +The RandReader implement [io.Reader]. +To provide predictable result, the RandReader is seeded with slice of +bytes. +A call to Read will fill the passed bytes with those seed. + +For example, given seed as "abc" (length is three), calling Read with +bytes length five will return "abcab". +-- + + +lib/sql: add new type Meta:: ++ +-- +Meta contains the DML meta data, including driver name, list of column +names, list of column holders, and list of values. + +The Meta type replace the Row type. +-- + + +lib/path: new package to work with path:: ++ +-- +The path package provide a new type Route, detached from "lib/http". + +A Route represent a parsed path. +A path can have a key, or binding, that can be replaced with string +value. +For example, "/org/:user/:repo" have two keys "user" and "repo". + +Route handle the path in case-insensitive manner. +-- + + +[#v0_53_0__bug_fixes] +=== Bug fixes + +_bin/go-mod-tip: use committer timestamp instead of author timestamp:: ++ +If the tip is rebased to upstream, the author timestamp is not changes, +but the commit timestamp changes. + + +[#v0_53_0__enhancements] +=== Enhancements + +lib/totp: add method GenerateWithTime and GenerateNWithTime:: ++ +The GenerateWithTime and GenerateNWithTime accept parameter +[time.Time] as the relative time for generated password. + + +lib/http: add support for If-Modified-Since in HandleFS:: ++ +If the node modification time is less than requested time value in +request header If-Modified-Since, server will response with +304 Not Modified. + + +lib/http: refactoring Range request, limit content served by server:: ++ +-- +When server receive, + + GET /big + Range: bytes=0- + +and the requested resources is quite larger, where writing all content of +file result in i/o timeout, it is best practice [1][2] if the server +write only partial content and let the client continue with the +subsequent Range request. + +In the above case, the server should response with, + + HTTP/1.1 206 Partial content + Content-Range: bytes 0-<limit>/<size> + Content-Length: <limit> + +Where limit is maximum packet that is reasonable [3] for most of the +client. +In this server we choose 8MB as limit. +-- + + +lib/http: add method Head to Client:: ++ +The Head method send the HEAD request to path, with optional +headers, and params in query parameters. + + +lib/ini: add method Keys:: ++ +The Keys method return sorted list of all section, subsection, and +variables as string where each of them separated by ":", for example +"section:sub:var". + + +[#v0_52_0] +== pakakeh.go v0.52.0 (2024-01-06) + +[#v0_52_0__new_features] +=== New features + +ssh/config: add method MarshalText and WriteTo:: ++ +-- +The MarshalText method encode the Section back to ssh_config format +with two spaces as indentation in key. + +The WriteTo method marshal the Section into text and write it to +[io.Writer] w. +-- + +lib/ssh: implement method Output on Client:: ++ +-- +The Output method run the command and return its standard output and +error as is. +Any other error beside standard error, like connection, will be returned +as error. +-- + +ssh/sftp: implement method MkdirAll on Client:: ++ +-- +The MkdirAll create directory on the server, from left to right. +Each directory is separated by '/', where the left part is the parent of +the right part. +This method is similar to [os.MkdirAll]. +-- + +cmd/httpdfs: implement [libhttp.Server] with [memfs.MemFS]:: ++ +-- +The httpdfs is a program to serve a directory under HTTP. +-- + +[#v0_52_0__breaking_changes] +=== Breaking changes + +ssh/config: refactoring the Config merge:: ++ +-- +This changes rename method [Config.Prepend] to [Config.Merge]. + +The way that how the other Config merged is changed. +Instead of appending all of other's sections into the current Config, +append the other Config instance to the current instance of Config. + +During [Config.Get] the top Config will be evaluated first, and then the +other Config is evaluated in order of Merge. +-- + +ssh/config: add parameter Config to NewSection:: ++ +-- +This changes how the Section and parser initialized. + +Previously, the Config depends on the parser to set the workDir and +homeDir and Section depends on Config only on Get; now its the other +way around, from top to bottom. +Config initialized first, then parser initialized using Config instance, +and then Section initialized also using Config instance. +-- + +lib/ssh: add parameter context to Execute method:: ++ +-- +This changes require the fork of our golang.org/x/crypto. +-- + +lib/time: remove UnixMicro and UnixMilli:: ++ +-- +Both of those methods has been added into standard library as +[Time.UnixMicro] and [Time.UnixMilli] since Go 1.17. +-- + +lib/io: removed, this package has been merged into "lib/os":: ++ +-- +While some functions are merged to "lib/os", some are not used anymore +like io.Reader. +-- + +lib/parser: removed, this package has been merged into lib/strings:: + + +[#v0_52_0__bug_fixes] +=== Bug fixes + +ssh/config: fix setting the default values:: ++ +-- +The field default value should be set on Get, after all the Host or +Match fields merged. +In this way, if the field key already set, its not overridden by the +default value or subsequent Host or Match value. +-- + +ssh/config: set the Hostname if its not set on [Config.Get]:: ++ +-- +Per manual ssh_config(5) on Hostname, + +[quote] +The default is the name given on the command line. + +So, if the requested host name match with one of Host or Match, but +Hostname is not set, it should be default to the requested parameter +name. +-- + +http/sseclient: fix data race on [Client.Close]:: ++ +-- +The data race happened when Close set conn to nil but the consume +method still on Read. +The fix is by waiting for 100ms so consume goroutine can check if closeq +is triggered from Close or not. +-- + +http/sseclient: fix Retry value not set to millisecond:: ++ +-- +When client receive "retry:" message, the value is in millisecond, but +when we store it we only convert it to [time.Duration] which default +to nanosecond. + +While at it, update comments on field [Client.Retry] and +[Client.Insecure]. +-- + +ssh/sftp: fix Stat on empty remote file name:: ++ +-- +The implementation of SSH server (openssh) for Stat is not consistent with +the RFC. +The RFC mentioned that + +[quote] +An empty path name is valid, and it refers to the user's default +directory (usually the user's home directory). + +But this only working on some command, like Mkdir, but not Stat. +-- + +ssh/sftp: fix non-nil returned error on Close:: ++ +-- +This changes fix the Close that always return an error. +-- + + +[#v0_52_0__enhancements] +=== Enhancements + +ssh/config: merge the Section slice values on [Section.merge]:: ++ +-- +Instead of using [Section.Set], set the key-value directly. + +While at it, merge the certificateFile, IdentityFile, knownHostFiles, +and sendEnv. +-- + +ssh/config: set the default UserKnownHostsFile in setDefaults:: ++ +-- +While at it, unfold each value of IdentityFile and UserKnownHostsFile +in setDefaults, by expanding "~" into user's home directory or joining +with "config" directory if its relative. +-- diff --git a/_doc/index.adoc b/_doc/index.adoc index 5f71f567..b6802b9e 100644 --- a/_doc/index.adoc +++ b/_doc/index.adoc @@ -41,6 +41,9 @@ This library is released every month, usually at the first week of month. link:CHANGELOG.html[Latest changelog^]. +link:CHANGELOG_2024.html[Changelog in 2023^]. +Changelog for `pakakeh.go` module since v0.42.0 until v0.58.1. + link:CHANGELOG_2023.html[Changelog in 2023^]. Changelog for `pakakeh.go` module since v0.43.0 until v0.51.0. |
