add examples about protecting internet-facing httpds
* request body size limit * request timeout
This commit is contained in:
parent
623df2b3cf
commit
c46038c51d
103
README.md
103
README.md
@ -1,6 +1,7 @@
|
|||||||
# sneak/styleguide
|
# sneak/styleguide
|
||||||
|
|
||||||
The following is the first released version of my personal code styleguide.
|
The following is the first released version of my personal code styleguide.
|
||||||
|
There are many like it, but this one is mine.
|
||||||
|
|
||||||
Only the Go portion is "complete". The others are mostly just
|
Only the Go portion is "complete". The others are mostly just
|
||||||
placeholders.
|
placeholders.
|
||||||
@ -237,8 +238,9 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
repo root.
|
repo root.
|
||||||
|
|
||||||
1. If you are writing a multi-module project, put all `.go` files in a
|
1. If you are writing a multi-module project, put all `.go` files in a
|
||||||
`pkg/` or `internal/` directory. This is to keep the root clean and to
|
`pkg/` or `internal/` subdirectory. `internal/` is for modules used
|
||||||
make it easier to see what is a library and what is a binary.
|
only by the current repo, and `pkg/` is for modules that can be consumed
|
||||||
|
externally. This is to keep the repo root as clean as possible.
|
||||||
|
|
||||||
1. Binaries go in `cmd/` directories. Each binary should have its own
|
1. Binaries go in `cmd/` directories. Each binary should have its own
|
||||||
directory. This is to keep the root clean and to make it easier to see
|
directory. This is to keep the root clean and to make it easier to see
|
||||||
@ -576,18 +578,73 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
|
|
||||||
## Other Golang Tips and Best Practices (Optional)
|
## Other Golang Tips and Best Practices (Optional)
|
||||||
|
|
||||||
|
1. For any internet-facing http server, set appropriate timeouts and limits
|
||||||
|
to protect against slowloris attacks or huge uploads that can consume
|
||||||
|
server resources even without authentication.
|
||||||
|
|
||||||
|
Example to limit request body size:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Limit the request body to 10MB
|
||||||
|
r.Body = http.MaxBytesReader(w, r.Body, 10<<20)
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
http.Error(w, "Request body too large", http.StatusRequestEntityTooLarge)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Fprintf(w, "Hello, World!")
|
||||||
|
})
|
||||||
|
|
||||||
|
http.ListenAndServe(":8080", nil)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Example to set appropriate timeouts:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
server := &http.Server{
|
||||||
|
Addr: ":8080",
|
||||||
|
ReadTimeout: 5 * time.Second,
|
||||||
|
WriteTimeout: 10 * time.Second,
|
||||||
|
Handler: http.DefaultServeMux,
|
||||||
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprintf(w, "Hello, World!")
|
||||||
|
})
|
||||||
|
|
||||||
|
server.ListenAndServe()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
1. When passing channels to goroutines, use read-only (`<-chan`) or
|
1. When passing channels to goroutines, use read-only (`<-chan`) or
|
||||||
write-only (`chan<-`) channels to communicate the direction of data flow
|
write-only (`chan<-`) channels to communicate the direction of data flow
|
||||||
clearly.
|
clearly.
|
||||||
|
|
||||||
2. Use `io.MultiReader` to concatenate multiple readers and
|
1. Use `io.MultiReader` to concatenate multiple readers and
|
||||||
`io.MultiWriter` to duplicate writes to multiple writers. This can
|
`io.MultiWriter` to duplicate writes to multiple writers. This can
|
||||||
simplify the handling of multiple data sources or destinations.
|
simplify the handling of multiple data sources or destinations.
|
||||||
|
|
||||||
3. For simple counters and flags, use the `sync/atomic` package to avoid
|
1. For simple counters and flags, use the `sync/atomic` package to avoid
|
||||||
the overhead of mutexes.
|
the overhead of mutexes.
|
||||||
|
|
||||||
4. When using mutexes, minimize the scope of locking to reduce contention
|
1. When using mutexes, minimize the scope of locking to reduce contention
|
||||||
and potential deadlocks. Prefer to lock only the critical sections of
|
and potential deadlocks. Prefer to lock only the critical sections of
|
||||||
code. Try to encapsulate the critical section in its own function or
|
code. Try to encapsulate the critical section in its own function or
|
||||||
method. Acquire the lock as the first line of the function, defer
|
method. Acquire the lock as the first line of the function, defer
|
||||||
@ -596,61 +653,61 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
using mutexes in the middle of a function. In short, build atomic
|
using mutexes in the middle of a function. In short, build atomic
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
5. Design types to be immutable where possible. This can help avoid issues
|
1. Design types to be immutable where possible. This can help avoid issues
|
||||||
with concurrent access and make the code easier to reason about.
|
with concurrent access and make the code easier to reason about.
|
||||||
|
|
||||||
6. Global state can lead to unpredictable behavior and makes the code
|
1. Global state can lead to unpredictable behavior and makes the code
|
||||||
harder to test. Use dependency injection to manage state.
|
harder to test. Use dependency injection to manage state.
|
||||||
|
|
||||||
7. Avoid using `init` functions unless absolutely necessary as they can
|
1. Avoid using `init` functions unless absolutely necessary as they can
|
||||||
lead to unpredictable initialization order and make the code harder to
|
lead to unpredictable initialization order and make the code harder to
|
||||||
understand.
|
understand.
|
||||||
|
|
||||||
8. Provide comments for all public interfaces explaining what they do and
|
1. Provide comments for all public interfaces explaining what they do and
|
||||||
how they should be used. This helps other developers understand the
|
how they should be used. This helps other developers understand the
|
||||||
intended use.
|
intended use.
|
||||||
|
|
||||||
9. Be mindful of resource leaks when using `time.Timer` and `time.Ticker`.
|
1. Be mindful of resource leaks when using `time.Timer` and `time.Ticker`.
|
||||||
Always stop them when they are no longer needed.
|
Always stop them when they are no longer needed.
|
||||||
|
|
||||||
10. Use `sync.Pool` to manage a pool of reusable objects, which can help
|
1. Use `sync.Pool` to manage a pool of reusable objects, which can help
|
||||||
reduce GC overhead and improve performance in high-throughput scenarios.
|
reduce GC overhead and improve performance in high-throughput scenarios.
|
||||||
|
|
||||||
11. Avoid using large buffer sizes for channels. Unbounded channels can
|
1. Avoid using large buffer sizes for channels. Unbounded channels can
|
||||||
lead to memory leaks. Use appropriate buffer sizes based on the
|
lead to memory leaks. Use appropriate buffer sizes based on the
|
||||||
application's needs.
|
application's needs.
|
||||||
|
|
||||||
12. Always handle the case where a channel might be closed. This prevents
|
1. Always handle the case where a channel might be closed. This prevents
|
||||||
panic and ensures graceful shutdowns.
|
panic and ensures graceful shutdowns.
|
||||||
|
|
||||||
13. For small structs, use value receivers to avoid unnecessary heap
|
1. For small structs, use value receivers to avoid unnecessary heap
|
||||||
allocations. Use pointer receivers for large structs or when mutating
|
allocations. Use pointer receivers for large structs or when mutating
|
||||||
the receiver.
|
the receiver.
|
||||||
|
|
||||||
14. Only use goroutines when necessary. Excessive goroutines can lead to
|
1. Only use goroutines when necessary. Excessive goroutines can lead to
|
||||||
high memory consumption and increased complexity.
|
high memory consumption and increased complexity.
|
||||||
|
|
||||||
15. Use `sync.Cond` for more complex synchronization needs that cannot be
|
1. Use `sync.Cond` for more complex synchronization needs that cannot be
|
||||||
met with simple mutexes and channels.
|
met with simple mutexes and channels.
|
||||||
|
|
||||||
16. Reflection is powerful but should be used sparingly as it can lead to
|
1. Reflection is powerful but should be used sparingly as it can lead to
|
||||||
code that is hard to understand and maintain. Prefer type-safe
|
code that is hard to understand and maintain. Prefer type-safe
|
||||||
solutions.
|
solutions.
|
||||||
|
|
||||||
17. Avoid storing large or complex data in context. Context should be used
|
1. Avoid storing large or complex data in context. Context should be used
|
||||||
for request-scoped values like deadlines, cancellation signals, and
|
for request-scoped values like deadlines, cancellation signals, and
|
||||||
authentication tokens.
|
authentication tokens.
|
||||||
|
|
||||||
18. Use `runtime.Callers` and `runtime.CallersFrames` to capture stack
|
1. Use `runtime.Callers` and `runtime.CallersFrames` to capture stack
|
||||||
traces for debugging and logging purposes.
|
traces for debugging and logging purposes.
|
||||||
|
|
||||||
19. Use the `testing.TB` interface to write helper functions that can be
|
1. Use the `testing.TB` interface to write helper functions that can be
|
||||||
used with both `*testing.T` and `*testing.B`.
|
used with both `*testing.T` and `*testing.B`.
|
||||||
|
|
||||||
20. Use struct embedding to reuse code across multiple structs. This is a
|
1. Use struct embedding to reuse code across multiple structs. This is a
|
||||||
form of composition that can simplify code reuse.
|
form of composition that can simplify code reuse.
|
||||||
|
|
||||||
21. Prefer defining explicit interfaces in your packages rather than
|
1. Prefer defining explicit interfaces in your packages rather than
|
||||||
relying on implicit interfaces. This makes the intended use of
|
relying on implicit interfaces. This makes the intended use of
|
||||||
interfaces clearer and the code more maintainable.
|
interfaces clearer and the code more maintainable.
|
||||||
|
|
||||||
@ -665,3 +722,5 @@ Feedback and suggestions are not only welcome but explicitly encouraged.
|
|||||||
Do with it what you will. There is no warranty, express or implied,
|
Do with it what you will. There is no warranty, express or implied,
|
||||||
including but not limited to merchantability or fitness for a particular
|
including but not limited to merchantability or fitness for a particular
|
||||||
purpose. Use at your own risk.
|
purpose. Use at your own risk.
|
||||||
|
|
||||||
|
# Credit
|
||||||
|
Loading…
Reference in New Issue
Block a user