| Age | Commit message (Collapse) | Author |
|
Previous struct size is 384 pointer bytes, now realign to 336 bytes
(-48 bytes).
|
|
In the `ServerOptions`, we add option `ShutdownIdleDuration` when set to
non-zero value it will start a timer.
When the timer expired, the server will stop accepting new connection and
then shutting down.
This allow de-activating HTTP server when no connections received after
specific duration to reduce the system resources.
|
|
The BasePath allow server to serve HTTP from custom prefix, other than
"/".
Each request that server received will remove the BasePath first
from the [http.Request.URL.Path] before passing to the handler.
Each redirect that server sent will add the BasePath as the prefix
to redirect URL.
Any trailing slash in the BasePath will be removed.
|
|
According to MDN [Redirections in HTTP], the HTTP status 302 Found use
case is
The Web page is temporarily unavailable for unforeseen reasons.
This probably to re-route the page until the original page is fixed.
While HTTP status 301 is for
Reorganization of a website.
Since the redirection in HandleFS only happen when user access directory
without slash, we should make it permanent.
[Redirections in HTTP]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Redirections
|
|
Previously, if request to directory does not end with "/", the HTTP
server will return the index.html of that directory.
This cause relative link inside the index.html broken when visited from
browser.
This changes make the request to directory always end with "/" by
redirecting the request with status 303 Found.
|
|
The field Listener allow user to pass [net.Listener] for accepting new
connection using [http.Serve] or [http.ServeTLS].
|
|
Non-zero status code indicates that the function already response
to the request, and the server will return immediately.
Zero status code indicates that the function did not process the request,
it is up to server to process the returned node `out`.
|
|
On server with TryDirect is true, any GET request to a directory should
always rescan the content and the generate the new index.html.
While at it, return the generated time in UTC instead of local time.
|
|
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.
|
|
The second return valus is a boolean to indicate that node is directory,
which can also retrieved from Node using method IsDir.
|
|
The MemFS always store directory without slash.
If caller request a directory node with slash, it will always return nil.
|
|
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
}
|
|
The reason is to make storing or encoding the RequestMethod value readable
from user point of view instead of number, 0, 1, 2, etc.
|
|
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.
|
|
Once the endpoint registered, the caller should not able to changes
any values on endpoint again.
|
|
This is to decoupling between ServerOptions and Server handlers.
|
|
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.
|
|
For HTTP server that use TLS, set the minimum TLS version and
ReadHeaderTimeout to mitigate slowloris attack.
For HTTP client or server that parameterize the use of InsecureSkipVerify,
annotate the line with "nolint:gosec" to allow the code pass the check.
Library that still use sha1, in example in DKIM and TOTP, skip the
warnings by annotating the line with "nolint:gosec".
A pointer variable now allocated their address before assigning its
value.
Any error that returned now wrapped using "%w".
Also, replace error checking using [errors.Is] or [errors.As] instead of
using equal or not-equal operators.
In "lib/http", replace any usage of "math/rand" with "crypto/rand".
Any call of [math/big.Rat.SetString] now annotated with "nolint:gosec"
since its false positive, the issue has been fixed in Go >= 1.17.7.
Any switch case that does not cover the rest of the possible values now
handled by adding the cases or by replacing the "default" case with
the rest of values.
|
|
HTTP request now implicitly create request with context.
Any false positive related to not closing HTTP response body has been
annotated with "nolint:bodyclose".
In the example code, use consistent "// Output:" comment format, by
prefixing with single space.
Any comment on code now also prefixing with single space.
An error returned without variables now use [errors.New] instead of
[fmt.Errorf].
Any error returned using [fmt.Errorf] now wrapped using "%w" instead of
"%s".
Also, replace error checking using [errors.Is] or [errors.As], instead
of using equal/not-equal operator.
Any statement like "x = x OP y" now replaced with "x OP= y".
Also, swap statement is simplified using "x, y = y, x".
Any switch statement with single case now replaced with if-condition.
Any call to defer on function or program that call [os.Exit], now
replaced by calling the deferred function directly.
Any if-else condition now replaced with switch statement, if possible.
|
|
Instead of annotating the lines that caught by linters, fix it to comply
with the recommendations.
This causes several breaking changes, especially 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]
|
|
There are several reasons that why we move from github.com.
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.
The GitHub Terms of Service [1], 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 regarding scraping the copyleft license [2].
[1]: https://docs.github.com/en/site-policy/github-terms/github-terms-of-service#4-license-grant-to-us
[2]: https://githubcopilotinvestigation.com
|
|
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.
|
|
If the node modification time is less than requested time value in
request header If-Modified-Since, server will response with
304 Not Modified.
|
|
|
|
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.
[1]: https://stackoverflow.com/questions/63614008/how-best-to-respond-to-an-open-http-range-request
[2]: https://bugzilla.mozilla.org/show_bug.cgi?id=570755
[3]: https://docs.aws.amazon.com/whitepapers/latest/s3-optimizing-performance-best-practices/use-byte-range-fetches.html
|
|
There are some reports that I disagree with revive, in example, code
should not declare the type after variables.
In my opinion, on some cases, declaring the type make the code more
readable and explicit.
Since I did not want to add new configuration file, we changes it and
follow revive for now.
|
|
For server SSE, we add new type SSEEndpoint, for registering endpoint
that can handle SSE.
For client SSE, we add it in new sub package "sseclient".
Implements: https://todo.sr.ht/~shulhan/share/1
Implements: https://todo.sr.ht/~shulhan/share/2
Signed-off-by: Shulhan <ms@kilabit.info>
|
|
In 06e6cbdd511c, we redirect request by adding end slash to the path
if the requested resource is directory, but somehow we miss adding the
original request query.
This changes fix this issue.
|
|
If request path is a directory and it is not end with slash, redirect
request to location with slash to allow relative links works inside the
HTML content.
For example, a "/page/index.html" contains links href="sub.html" (where
"sub.html" is inside "/page" directory).
If request to "/page" (without end with slash) return content of
"/page/index.html", then when user click on sub.html it will request to
"/sub.html" instead of "/page/sub.html".
|
|
Using global debug value for all packages turns out is not a good
idea.
|
|
We use the mlog, so user that also use mlog can record the error.
|
|
While at it, add comment for function generateFormData and Server method
handleHead.
|
|
For HTTP Server using HandleFS, the Range request is handled
automatically.
For other HTTP server, user can use the HandleRange function.
The HandleRange function handle [HTTP Range] request using "bytes" unit.
The body parameter contains the content of resource being requested that
accept Seek method.
If the Request method is not GET, or no Range in header request it will
return all the body [RFC7233 S-3.1].
The contentType is optional, if its empty, it will detected by
http.ResponseWriter during Write.
[HTTP Range]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests
[RFC7233 S-3.1]: https://datatracker.ietf.org/doc/html/rfc7233#section-3.1
# Conflicts:
# CHANGELOG.adoc
|
|
This is for clarity in the code, better to be explicit by typing where
the field or methods come from.
|
|
If the EnableIndexHtml in the ServeOptions enabled, server generate
list of files inside the requested path as HTML.
|
|
|
|
Since Go 1.16, the ioutil package has been deprecated.
This changes replace any usage that use functions from ioutil package
with their replacement from package os or package io.
|
|
This changes rename ServerOptions field FSAuthHandler to FSHandler and
rewrite their usage.
The FSHandler define the function to inspect each GET request to Server
MemFS instance.
The node parameter contains the requested file inside the memfs.
If the handler return true, server will continue processing the node
(writing the Node content type, body, and so on).
If the handler return false, server stop processing the node and return
immediately, which means the function should have already handle writing
the header, status code, and/or body.
|
|
The FSAuthHandler in the ServerOptions define a function that will
be called to each GET request to Server Memfs instance using the value
from the HTTP Request instance.
If the request is not authorized it must return false and the HTTP
response will be set to 401 Unauthorized with empty body.
|
|
In case the consumer of lib/http package use mlog for logging, the
log will be written to their predefined writers.
In case they did not use mlog, the log will written to stdout and stderr.
|
|
This options is duplicate with Memfs.Opts.
|
|
The original idea for option ContentEncoding in EmbedOptions and Node
is to save spaces, compressing the content on disk on embedding and
doing transport, when the MemFS instance is used to serve the (embedded)
contents of file system.
This option turns out break the HTTP content negotiation [1] of
accept-encoding header, if the HTTP server does not handle it properly,
which default Go HTTP server does not.
In order to prevent this issue in the future, for anyone who use the
memfs for serving static HTTP contents, we remove the options and store
the embedded content as is and let the HTTP server handle how the
compression by itself.
[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation
|
|
The reason why the field named V is because it's short. It's come
from my C/C++ experience that got carried away when writing this
package.
Now, after having more time writing Go, I prefer clarity over
cleverity(?).
|
|
If the Server handle file system using MemFS, server will set the
ETag [1] header using the file epoch as value.
On the next request, server will compare the request header
If-None-Match with the requested file epoch. If its equal server will
return the response as 304 StatusNotModified.
[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
|
If the Endpoint set the RequestType to RequestTypeXML, the response
header should be set to ContentTypeXML.
|
|
On c8dd20254d, we check the request path by adding .html suffix but
forgot to return node if its not nil.
|
|
Previously, if the request path is not exist we check if request
contains index.html and if still not exist we return nil.
This commit add another check by appending ".html" to the request path.
So, for example, if path "/x" not exist in memfs, we check if
"/x/index.html". If its still not exist, we check "/x.html".
|
|
Now that Options field has been exported, we did not need to have
duplicate Memfs, so this field is removed in favor of Options.Memfs.
|
|
Previously, the Options field is not exported to prevent user from
changing it once it set throught NewServer() function.
This changes export the Options field to allow user of Server access its
values. We can create a method on server to return read-only options,
but that will over complicated the Server API.
|
|
The CORS options are optional and rarely used, its usually handled
by proxy. So, we move them to separate struct to make the actual
server options short.
|