Full Code of Kwynto/gosession for AI

main 7822ad47b237 cached
26 files
61.9 KB
19.5k tokens
87 symbols
1 requests
Download .txt
Repository: Kwynto/gosession
Branch: main
Commit: 7822ad47b237
Files: 26
Total size: 61.9 KB

Directory structure:
gitextract_1luo0k9u/

├── .github/
│   └── workflows/
│       └── go.yaml
├── .gitignore
├── LICENSE
├── README.md
├── go.mod
├── gosession.go
├── gosession_test.go
└── pkg/
    └── examples/
        ├── example1/
        │   ├── go.mod
        │   ├── go.sum
        │   └── main.go
        ├── example2/
        │   ├── go.mod
        │   ├── go.sum
        │   └── main.go
        └── example3/
            ├── cmd/
            │   └── web/
            │       ├── handlers.go
            │       ├── helpers.go
            │       ├── main.go
            │       ├── routes.go
            │       └── templates.go
            ├── go.mod
            ├── go.sum
            └── ui/
                ├── html/
                │   ├── base.layout.tmpl
                │   ├── footer.partial.tmpl
                │   ├── home.page.tmpl
                │   └── homeauth.page.tmpl
                └── static/
                    ├── css/
                    │   └── main.css
                    └── js/
                        └── main.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/workflows/go.yaml
================================================
# This workflow will build a golang project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-go

name: GoCoverage # The name of the workflow that will appear on Github

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: '1.20'

    - name: Build
      run: go build -v ./...

    - name: Test
      run: go test -coverprofile="coverage.txt" -v ./...
    
    - name: Upload coverage reports to Codecov
      uses: codecov/codecov-action@v3
      env:
        CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}


================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, built with `go test -c`
*.test

# Output of the go coverage tool
*.out
PR


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2022 Constantine Zavezeon <kwynto@mail.ru>


Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

================================================
FILE: README.md
================================================
# GoSession
This is quick session for net/http in GoLang.  
This package is perhaps the best implementation of the session mechanism, at least it tries to become one.  

[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge.svg)](https://github.com/avelino/awesome-go)
[![GoDoc](https://godoc.org/github.com/Kwynto/gosession?status.svg)](https://godoc.org/github.com/Kwynto/gosession)
[![Go Report Card](https://goreportcard.com/badge/github.com/Kwynto/gosession)](https://goreportcard.com/report/github.com/Kwynto/gosession)
[![GitHub](https://img.shields.io/github/license/Kwynto/gosession)](https://github.com/Kwynto/gosession/blob/master/LICENSE)
[![codecov](https://codecov.io/gh/Kwynto/gosession/branch/main/graph/badge.svg?token=TXP2NOMK58)](https://codecov.io/gh/Kwynto/gosession) 

**Important note**
This package is designed to work with the standard net/http package and has not been tested with other http packages by the developer.

## Contents

- [GoSession](#gosession)
  - [Contents](#contents)
  - [What are sessions and why are they needed](#what-are-sessions-and-why-are-they-needed)
  - [How to connect GoSession](#how-to-connect-gosession)
  - [How to use GoSession](#how-to-use-gosession)
  - [Examples of using](#examples-of-using)
    - [Example 1:](#example-1)
    - [Example 2:](#example-2)
    - [Example 3:](#example-3)
  - [About the package](#about-the-package)
  - [About the author](#about-the-author)

## What are sessions and why are they needed
A session on a site is a good method of identifying a site user.  
A session is often used to authorize a user and retain their identity until the user closes the browser page.  
While the user is working with the site, he saves cookies with a unique identifier, by this identifier one can distinguish one user from another and the server can store special data for a particular user.  
User data received during the session period can be used for authorization, marketing and many other cases when it is necessary to collect, process and analyze data about a specific user.  
A session is an efficient method of interacting with a user.

**[⬆ back to top](#gosession)** - **[⬆ back to the chapter](#what-are-sessions-and-why-are-they-needed)**

## How to connect GoSession
In your project folder, initialize the Go-module with the command
> go mod init your_app_name

Download and install GoSession
> go get github.com/Kwynto/gosession

Now you can add the GoSession package to your Go-code file, for example in `main.go`
```go
import "github.com/Kwynto/gosession"
```

**[⬆ back to top](#gosession)** - **[⬆ back to the chapter](#how-to-connect-gosession)**

## How to use GoSession
To use the GoSession package, you need to import it into your code.
```go
import "github.com/Kwynto/gosession"
```

All operations for working with sessions must be called from handlers.  
Each time you start working with the session store, you need to call `gosession.Start(w *http.ResponseWriter, r *http.Request)`, since this function returns the identifier of the store and allows you to access the elements of the store through the identifier.
```go
id := gosession.Start(&w, r)
```

You need to call the `gosession.Start(w *http.ResponseWriter, r *http.Request)` function from the handler
```go
func rootHandler(w http.ResponseWriter, r *http.Request) {
  id := gosession.Start(&w, r) // Get the storage ID for a specific user

  html := "<html><head><title>Title</title></head><body>%s</body></html>"
  fmt.Fprintf(w, html, id)
}
```

Alternatively, you can use the `gosession.StartSecure(w *http.ResponseWriter, r *http.Request)` function instead of `gosession.Start(w, r)`.  
The `StartSecure()` function replaces the session ID each time it is accessed, which reduces the possibility of ID hijacking.  
The use of these functions is exactly the same.  
```go
id := gosession.StartSecure(&w, r)
```

You need to call the `gosession.StartSecure()` function from the handler  
```go
func rootHandler(w http.ResponseWriter, r *http.Request) {
  id := gosession.StartSecure(&w, r) // Get the storage ID for a specific user

  html := "<html><head><title>Title</title></head><body>%s</body></html>"
  fmt.Fprintf(w, html, id)
}
```

Once you have a store ID, you can write variables to the store, read them, and delete them.

Recording is done using the `Set(name string, value interface{})` method
```go
id.Set("name variable", anyVariable)
```

In the handler it looks like this
```go
func writeHandler(w http.ResponseWriter, r *http.Request) {
  name := "username"
  username := "JohnDow"

  id := gosession.Start(&w, r)
  id.Set(name, username)

  html := "<html><head><title>Title</title></head><body>OK</body></html>"
  fmt.Fprint(w, html)
}
```

Reading is done by `Get(name string) interface{}` method for one variable  
and the `GetAll() Session` method to read all session variables
```go
anyVariable := id.Get("name variable")
```

```go
allVariables := id.GetAll()
```

In the handler it looks like this
```go
func readHandler(w http.ResponseWriter, r *http.Request) {
  name := "username"
  var username interface{}

  id := gosession.Start(&w, r)
  username = id.Get(name) // Reading the "username" variable from the session for a specific user

  html := "<html><head><title>Title</title></head><body>%s</body></html>"
  fmt.Fprintf(w, html, username)
}
```

or so
```go
func readHandler(w http.ResponseWriter, r *http.Request) {
  var tempStr string = ""

  id := gosession.Start(&w, r)
  allVariables := id.GetAll() // Reading the entire session for a specific client

  for i, v := range allVariables {
    tempStr = fmt.Sprint(tempStr, i, "=", v, "<br>")
  }
  html := "<html><head><title>Title</title></head><body>%s</body></html>"
  fmt.Fprintf(w, html, tempStr)
}
```

Removing an entry from a session of a specific client is carried out using the `Remove(name string)` method
```go
id.Remove("name variable")
```

In the handler it looks like this
```go
func removeHandler(w http.ResponseWriter, r *http.Request) {
  id := gosession.Start(&w, r)
  id.Remove("name variable") // Removing a variable from a specific client session

  html := "<html><head><title>Title</title></head><body>OK</body></html>"
  fmt.Fprint(w, html)
}
```

Removing the entire session of a specific client is done using the `Destroy(w *http.ResponseWriter)` method
```go
id.Destroy(&w)
```

In the handler it looks like this
```go
func destroyHandler(w http.ResponseWriter, r *http.Request) {
  id := gosession.Start(&w, r)
  id.Destroy(&w) // Deleting the entire session of a specific client

  html := "<html><head><title>Title</title></head><body>OK</body></html>"
  fmt.Fprint(w, html)
}
```

GoSession allows you to change its settings with the `SetSettings(setings GoSessionSetings)` function,  
which is used outside of the handler, for example, inside the `main()` function
```go
var mySetingsSession = gosession.GoSessionSetings{
  CookieName:    gosession.GOSESSION_COOKIE_NAME,
  Expiration:    gosession.GOSESSION_EXPIRATION,
  TimerCleaning: gosession.GOSESSION_TIMER_FOR_CLEANING,
}

gosession.SetSetings(mySetingsSession) // Setting session preferences
```

GoSession has 3 constants available for use
```go
const (
  GOSESSION_COOKIE_NAME        string        = "SessionId" // Name for session cookies
  GOSESSION_EXPIRATION         int64         = 43_200      // Max age is 12 hours.
  GOSESSION_TIMER_FOR_CLEANING time.Duration = time.Hour   // The period of launch of the mechanism of cleaning from obsolete sessions
)
```

The remaining functions, types and variables in GoSession are auxiliary and are used only within the package.

**[⬆ back to top](#gosession)** - **[⬆ back to the chapter](#how-to-use-gosession)**

## Examples of using

### Example 1:
*This is a simple authorization example and it shows the use of the write and read session variables functions, as well as deleting the entire session.*

Download the GoSession project to your computer:
> git clone https://github.com/Kwynto/gosession.git

Go to the example folder or open this folder in your IDE.
> cd ./gosession/pkg/example1

Install GoSession
> go get github.com/Kwynto/gosession

Run:
> go mod tidy

Start the server:
> go run .

Visit site
> http://localhost:8080/

### Example 2:
*This example shows a primitive way to collect information about user actions. You can collect any public user data, as well as track user actions, and then save and process this data.*

Download the GoSession project to your computer:
> git clone https://github.com/Kwynto/gosession.git

Go to the example folder or open this folder in your IDE.
> cd ./gosession/pkg/example2

Install GoSession
> go get github.com/Kwynto/gosession

Run:
> go mod tidy

Start the server:
> go run .

Visit site
> http://localhost:8080/

Now you can follow the links on this site and see how the site saves and shows your browsing history.

### Example 3:
*This example shows a simple, realistic site that uses the session mechanism.*

Download the GoSession project to your computer:
> git clone https://github.com/Kwynto/gosession.git

Go to the example folder or open this folder in your IDE.
> cd ./gosession/pkg/example3

Install GoSession
> go get github.com/Kwynto/gosession

Run:
> go mod tidy

Start the server:
> go run ./cmd/web/

Visit site
> http://localhost:8080/

Now you can follow the links on this site.

**[⬆ back to top](#gosession)** - **[⬆ back to the chapter](#examples-of-using)**

## About the package

GoSession has a description of its functionality in a `README.md` file and internal documentation.  
GoSession is tested and has a performance check.  
You can use the GoSession tests and documentation yourself.

Download the GoSession project to your computer:
> git clone https://github.com/Kwynto/gosession.git

Go to the project folder:
> cd ./gosession

**Check out the documentation**

Look at the documentation in two steps.  
First, in the console, run:
> godoc -http=:8080

And then in your web browser navigate to the uri:
> http://localhost:8080

*The `godoc` utility may not be present in your Go build and you may need to install it  
command `go get -v golang.org/x/tools/cmd/godoc`*

**For Debian Linux users (Ubuntu, Mint and others):** *You may need to install the tools with the `sudo apt install golang-golang-x-tools` command* 

You can also use Go's standard functionality to view documentation in the console via `go doc`.  
For example:  
> go doc Start

If your IDE is good enough, then the documentation for functions and methods will be available from your code editor.

**Testing**

Run tests:
> go test -v

Run tests showing code coverage:
> go test -cover -v

You can view code coverage in detail in your web browser.  
To do this, you need to sequentially execute two commands in the console:
> go test -coverprofile="coverage.out" -v  
> go tool cover -html="coverage.out"

**Performance**

You can look at code performance tests:
> go test -benchmem -bench="." gosession.go gosession_test.go

*The slowest of all functions is `cleaningSessions()`, but this should not scare you, as it is a utility function and is rarely executed. This function does not affect the performance of the entire mechanism, it is only needed to clean up the storage from lost sessions.*

**[⬆ back to top](#gosession)** - **[⬆ back to the chapter](#about-the-package)**

## Support the author

You can support open source projects and the author of this project. The details are [here](https://github.com/Kwynto/Kwynto/blob/main/SUPPORT.md).  

## About the author

The author of the project is Constantine Zavezeon (Kwynto).  
You can contact the author by e-mail: kwynto@mail.ru  
The author accepts proposals for participation in open source projects,  
as well as willing to accept job offers.
If you want to offer me a job, then first I ask you to read [this](https://github.com/Kwynto/Kwynto/blob/main/offer.md).

**[⬆ back to top](#gosession)**

================================================
FILE: go.mod
================================================
module github.com/Kwynto/gosession

go 1.17


================================================
FILE: gosession.go
================================================
// This is quick session for net/http in golang.
// This package is perhaps the best implementation of the session mechanism, at least it tries to become one.
package gosession

// --------------------------------------------------------
// Copyright (c) 2022 Constantine Zavezeon <kwynto@mail.ru>
// --------------------------------------------------------

import (
	"crypto/rand"
	"fmt"
	"net/http"
	"sync"
	"time"
)

const (
	GOSESSION_COOKIE_NAME        string        = "SessionId" // Name for session cookies
	GOSESSION_EXPIRATION         int64         = 43_200      // Max age is 12 hours.
	GOSESSION_TIMER_FOR_CLEANING time.Duration = time.Hour   // The period of launch of the mechanism of cleaning from obsolete sessions
)

// The SessionId type is the session identifier
type SessionId string

// The Session type contains variables defined for session storage for each client.
type Session map[string]interface{}

// The internalSession type is the internal server representation of the session
type internalSession struct {
	expiration int64
	data       Session
}

// The serverSessions type is intended to describe all sessions of all client connections
type serverSessions map[SessionId]internalSession

// The GoSessionSetings type describes the settings for the session system
type GoSessionSetings struct {
	CookieName    string
	Expiration    int64
	TimerCleaning time.Duration
}

// The allSessions variable stores all sessions of all clients
var allSessions serverSessions = make(serverSessions, 0)

// Session mechanism settings variable
var setingsSession = GoSessionSetings{
	CookieName:    GOSESSION_COOKIE_NAME,
	Expiration:    GOSESSION_EXPIRATION,
	TimerCleaning: GOSESSION_TIMER_FOR_CLEANING,
}

var block sync.RWMutex

// The generateId() generates a new session id in a random, cryptographically secure manner
func generateId() SessionId {
	b := make([]byte, 32)
	rand.Read(b)
	return SessionId(fmt.Sprintf("%x", b))
}

// The getOrSetCookie(w, r) gets the session id from the cookie, or creates a new one if it can't get
func getOrSetCookie(w *http.ResponseWriter, r *http.Request) SessionId {
	data, err := r.Cookie(setingsSession.CookieName)
	if err != nil {
		id := generateId()
		cookie := &http.Cookie{
			Name:   setingsSession.CookieName,
			Value:  string(id),
			MaxAge: 0,
		}
		http.SetCookie(*w, cookie)
		return id
	}
	return SessionId(data.Value)
}

// The deleteCookie(w) function deletes the session cookie
func deleteCookie(w *http.ResponseWriter) {
	cookie := &http.Cookie{
		Name:   setingsSession.CookieName,
		Value:  "",
		MaxAge: -1,
	}
	http.SetCookie(*w, cookie)
}

// The cleaningSessions() function periodically cleans up the server's session storage
func cleaningSessions() {
	presently := time.Now().Unix()
	block.Lock()
	for id, ses := range allSessions {
		if ses.expiration < presently {
			delete(allSessions, id)
		}
	}
	block.Unlock()
	// log.Println("Session storage has been serviced.")
	time.AfterFunc(setingsSession.TimerCleaning, cleaningSessions)
}

// The writeS() method safely writes data to the session store
func (id SessionId) writeS(iSes internalSession) {
	block.Lock()
	allSessions[id] = iSes
	block.Unlock()
}

// The readS() method safely reads data from the session store.
func (id SessionId) readS() (internalSession, bool) {
	block.RLock()
	defer block.RUnlock()
	ses, ok := allSessions[id]
	if !ok {
		return internalSession{}, false
	}
	return ses, true
}

// The destroyS() method safely deletes the entire session from the store.
func (id SessionId) destroyS() {
	block.Lock()
	delete(allSessions, id)
	block.Unlock()
}

// The deleteS() method safely deletes one client variable from the session by its name
// name - session variable name
func (id SessionId) deleteS(name string) {
	block.Lock()
	ses, ok := allSessions[id]
	if ok {
		delete(ses.data, name)
		allSessions[id] = ses
	}
	block.Unlock()
}

// The Set(name, value) SessionId-method to set the client variable to be stored in the session system.
// name - session variable name.
// value - directly variable in session.
func (id SessionId) Set(name string, value interface{}) {
	ses, ok := id.readS()
	if ok {
		ses.data[name] = value
		id.writeS(ses)
	}
}

// The GetAll() SessionId-method to get all client variables from the session system
func (id SessionId) GetAll() Session {
	ses, _ := id.readS()
	return ses.data
}

// The Get(name) SessionId-method to get a specific client variable from the session system.
// name - session variable name
func (id SessionId) Get(name string) interface{} {
	ses, _ := id.readS()
	return ses.data[name]
}

// The Destroy(w) SessionId-method to remove the entire client session
func (id SessionId) Destroy(w *http.ResponseWriter) {
	id.destroyS()
	deleteCookie(w)
}

// The Remove(name) SessionId-method to remove one client variable from the session by its name
func (id SessionId) Remove(name string) {
	id.deleteS(name)
}

// The SetSetings(settings) sets new settings for the session mechanism.
// setings - gosession.GoSessionSetings public type variable for setting new session settings
func SetSetings(setings GoSessionSetings) {
	setingsSession = setings
}

// The Start(w, r) function starts the session and returns the SessionId to the handler for further use of the session mechanism.
// This function must be run at the very beginning of the http.Handler
func Start(w *http.ResponseWriter, r *http.Request) SessionId {
	id := getOrSetCookie(w, r)
	ses, ok := id.readS()
	if !ok {
		ses.data = make(Session, 0)
	}
	presently := time.Now().Unix()
	ses.expiration = presently + setingsSession.Expiration
	id.writeS(ses)
	return id
}

// The StartSecure(w, r) function starts the session or changes the session ID and sets new cookie to the client.
// This function must be run at the very beginning of the http.Handler
func StartSecure(w *http.ResponseWriter, r *http.Request) SessionId {
	id := getOrSetCookie(w, r)
	ses, ok := id.readS()
	if !ok {
		ses.data = make(Session, 0)
		presently := time.Now().Unix()
		ses.expiration = presently + setingsSession.Expiration
		id.writeS(ses)
		return id
	} else {
		id.destroyS()
		id = generateId()
		cookie := &http.Cookie{
			Name:   setingsSession.CookieName,
			Value:  string(id),
			MaxAge: 0,
		}
		http.SetCookie(*w, cookie)
		presently := time.Now().Unix()
		ses.expiration = presently + setingsSession.Expiration
		id.writeS(ses)
		return id
	}
}

// Package initialization
func init() {
	time.AfterFunc(setingsSession.TimerCleaning, cleaningSessions)
	// log.Println("GoSessions initialized")
}


================================================
FILE: gosession_test.go
================================================
package gosession

// --------------------------------------------------------
// Copyright (c) 2022 Constantine Zavezeon <kwynto@mail.ru>
// --------------------------------------------------------

import (
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"net/http/httptest"
	"testing"
	"time"
)

const (
	GOSESSION_TESTING_ITER int = 100
)

// --------------
// Test functions
// --------------

func Test_generateId(t *testing.T) {
	testVar := make(map[int]SessionId)
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		testVar[i] = generateId() // calling the tested function
	}
	for _, v1 := range testVar {
		count := 0
		for _, v2 := range testVar {
			if v1 == v2 {
				count++
			}
			// if bytes.Equal([]byte(v1), []byte(v2)) {
			// 	count++
			// }
		}
		// work check
		if count > 1 {
			t.Error("Error generating unique identifier.")
		}
	}
}

func Test_getOrSetCookie(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		var ctrlId SessionId
		handler := func(w http.ResponseWriter, r *http.Request) {
			sesid := getOrSetCookie(&w, r) // calling the tested function
			ctrlId = sesid
			io.WriteString(w, string(sesid))
		}
		w := httptest.NewRecorder()
		r := httptest.NewRequest("GET", "/", nil)
		handler(w, r)

		status := w.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned %v", status)
		}

		cookies := w.Result().Cookies()
		noErr := false
		for _, v := range cookies {
			if v.Name == setingsSession.CookieName && v.Value == string(ctrlId) {
				noErr = true
			}
		}
		// work check
		if !noErr {
			t.Error("the server returned an invalid ID")
		}
	}

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		var ctrlId SessionId
		handler := func(w http.ResponseWriter, r *http.Request) {
			sesid := getOrSetCookie(&w, r) // calling the tested function
			ctrlId = sesid
			io.WriteString(w, string(sesid))
		}
		w := httptest.NewRecorder()
		r := httptest.NewRequest("GET", "/", nil)
		clientId := generateId()
		cookie := &http.Cookie{
			Name:   setingsSession.CookieName,
			Value:  string(clientId),
			MaxAge: 0,
		}
		r.AddCookie(cookie)
		handler(w, r)

		status := w.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned %v", status)
		}
		// work check
		if ctrlId != clientId {
			t.Error("server received invalid id")
		}
	}
}

func Test_deleteCookie(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		// handler := func(w http.ResponseWriter, r *http.Request) {
		handler := func(w http.ResponseWriter) {
			deleteCookie(&w) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}
		w := httptest.NewRecorder()
		// r := httptest.NewRequest("GET", "/", nil)
		clientId := generateId()
		// cookie := &http.Cookie{
		// 	Name:   setingsSession.CookieName,
		// 	Value:  string(clientId),
		// 	MaxAge: 0,
		// }
		// r.AddCookie(cookie)
		handler(w)

		status := w.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned %v", status)
		}

		cookies := w.Result().Cookies()
		noErr := true
		for _, v := range cookies {
			if v.Name == setingsSession.CookieName && v.Value == string(clientId) {
				noErr = false
			}
		}
		// work check
		if !noErr {
			t.Error("the server did not delete the session cookie")
		}
	}
}

func Test_cleaningSessions(t *testing.T) {
	rand.Seed(time.Now().Unix())
	var falseInd int
	var trueInd int
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		falseInd = rand.Intn(75)
		trueInd = rand.Intn(50) + falseInd

		for id := range allSessions {
			delete(allSessions, id)
		}

		for fi := 0; fi < falseInd; fi++ {
			allSessions[generateId()] = internalSession{
				expiration: 0,
				data:       make(Session),
			}
		}

		for ti := 0; ti < trueInd; ti++ {
			allSessions[generateId()] = internalSession{
				expiration: time.Now().Unix() + setingsSession.Expiration,
				data:       make(Session),
			}
		}

		cleaningSessions() // calling the tested function
		// work check
		if len(allSessions) != trueInd {
			t.Error("The number of correct entries does not match.")
		}
	}
}

func Test_writeS(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		ses := internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       make(Session),
		}
		id := generateId()
		id.writeS(ses)
		if allSessions[id].expiration != ses.expiration {
			t.Error("Writing error. Session is not equal.")
		}
	}
}

func Test_readS(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		ses := internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       make(Session),
		}
		id := generateId()
		allSessions[id] = ses
		res, _ := id.readS()
		if res.expiration != ses.expiration {
			t.Error("Reading error. Session is not equal.")
		}

		delete(allSessions, id)
		_, ok := id.readS()
		if ok {
			t.Error("Reading error. Was reaing wrong session.")
		}
	}
}

func Test_destroyS(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		ses := internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       make(Session),
		}
		id := generateId()
		id.writeS(ses)
		id.destroyS()
		_, ok := id.readS()
		if ok {
			t.Error("Destroy error. Was reading deleted session.")
		}
	}
}

func Test_deleteS(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		ses := internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       make(Session),
		}
		ses.data["name"] = "test string"
		id := generateId()
		id.writeS(ses)
		// id.destroyS()
		id.deleteS("name")

		_, ok := allSessions[id].data["name"]
		if ok {
			t.Error("Delete error. Was reading deleted variable.")
		}
	}
}

func Test_Set(t *testing.T) {
	var value interface{}
	rand.Seed(time.Now().Unix())

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		id := generateId()
		allSessions[id] = internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       make(Session),
		}

		name := "test variable"
		switch rand.Intn(3) {
		case 0:
			value = true
		case 1:
			value = fmt.Sprintf("test string %d", rand.Intn(100))
		case 2:
			value = rand.Intn(100)
		case 3:
			value = rand.Float64()
		}

		id.Set(name, value) // calling the tested function
		// work check
		if allSessions[id].data[name] != value {
			t.Error("Failed to write variable to session storage.")
		}
	}
}

func Test_GetAll(t *testing.T) {
	var value interface{}
	var name string
	rand.Seed(time.Now().Unix())

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		id := generateId()
		data := make(Session)
		count := rand.Intn(20) + 1
		for ic := 0; ic < count; ic++ {
			name = fmt.Sprintf("test name  %d", rand.Intn(100))
			switch rand.Intn(3) {
			case 0:
				value = true
			case 1:
				value = fmt.Sprintf("test string %d", rand.Intn(100))
			case 2:
				value = rand.Intn(100)
			case 3:
				value = rand.Float64()
			}
			data[name] = value
		}
		allSessions[id] = internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       data,
		}

		ses := id.GetAll() // calling the tested function
		// work check
		for iname, v := range ses {
			if v != data[iname] {
				t.Error("Incorrect data received from session variable storage")
			}
		}
	}
}

func Test_Get(t *testing.T) {
	var value interface{}
	var name string
	rand.Seed(time.Now().Unix())

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		id := generateId()
		data := make(Session)

		name = "test name"
		switch rand.Intn(4) {
		case 0:
			value = true
		case 1:
			value = fmt.Sprintf("test string %d", rand.Intn(100))
		case 2:
			value = rand.Intn(100)
		case 3:
			value = rand.Float64()
		}
		data[name] = value
		allSessions[id] = internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       data,
		}

		getedValue := id.Get(name) // calling the tested function
		// work check
		if getedValue != value {
			t.Error("Incorrect data received from session variable storage")
		}
	}
}

func Test_Destroy(t *testing.T) {
	var hid SessionId

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		w := httptest.NewRecorder()
		r := httptest.NewRequest("GET", "/", nil)
		id := generateId()
		cookie := &http.Cookie{
			Name:   setingsSession.CookieName,
			Value:  string(id),
			MaxAge: 0,
		}
		r.AddCookie(cookie)

		data := make(Session)
		name := "test name"
		value := "test value"
		data[name] = value
		allSessions[id] = internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       data,
		}

		handler := func(w http.ResponseWriter, r *http.Request) {
			hid = Start(&w, r)
			hid.Destroy(&w) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}
		handler(w, r)

		status := w.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned status: %v", status)
		}

		// work check
		if id != hid {
			t.Error("ID mismatch")
		}

		cookies := w.Result().Cookies()
		noErr := true
		for _, v := range cookies {
			if v.Name == setingsSession.CookieName && v.Value == string(id) {
				noErr = false
			}
		}
		// work check
		if !noErr {
			t.Error("The server did not delete the session cookie")
		}

		// work check
		if allSessions[id].data != nil {
			t.Error("Session has not been deleted.")
		}
	}
}

func Test_Remove(t *testing.T) {
	var value interface{}
	var name string
	rand.Seed(time.Now().Unix())

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		id := generateId()
		data := make(Session)

		name = "test name"
		switch rand.Intn(3) {
		case 0:
			value = true
		case 1:
			value = fmt.Sprintf("test string %d", rand.Intn(100))
		case 2:
			value = rand.Intn(100)
		case 3:
			value = rand.Float64()
		}
		data[name] = value
		allSessions[id] = internalSession{
			expiration: time.Now().Unix() + setingsSession.Expiration,
			data:       data,
		}

		id.Remove(name) // calling the tested function
		// work check
		if allSessions[id].data[name] == value {
			t.Error("Failed to change settings")
		}
	}
}

func Test_SetSetings(t *testing.T) {
	var test_setingsSession1 = GoSessionSetings{
		CookieName:    "test_name",
		Expiration:    int64(rand.Intn(86_400)),
		TimerCleaning: time.Minute,
	}
	var test_setingsSession2 = GoSessionSetings{
		CookieName:    GOSESSION_COOKIE_NAME,
		Expiration:    GOSESSION_EXPIRATION,
		TimerCleaning: GOSESSION_TIMER_FOR_CLEANING,
	}

	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		SetSetings(test_setingsSession1) // calling the tested function
		// work check
		if test_setingsSession1 != setingsSession {
			t.Error("Failed to change settings.")
		}
		SetSetings(test_setingsSession2) // calling the tested function
		// work check
		if test_setingsSession2 != setingsSession {
			t.Error("Failed to change settings.")
		}
	}
}

func Test_Start(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		var id1 SessionId
		var id2 SessionId
		handler1 := func(w http.ResponseWriter, r *http.Request) {
			id1 = Start(&w, r) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}
		handler2 := func(w http.ResponseWriter, r *http.Request) {
			id2 = Start(&w, r) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}

		w1 := httptest.NewRecorder()
		r1 := httptest.NewRequest("GET", "/", nil)
		handler1(w1, r1)

		status := w1.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned status: %v", status)
		}

		cookies := w1.Result().Cookies()
		var cookie *http.Cookie
		for _, v := range cookies {
			cookie = v
		}
		w2 := httptest.NewRecorder()
		r2 := httptest.NewRequest("GET", "/", nil)
		r2.AddCookie(cookie)
		handler2(w2, r2)

		status = w2.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned status: %v", status)
		}

		// work check
		if id1 != id2 {
			t.Errorf("Server and client IDs are not equal:\n server: %v\n client: %v\n", id1, id2)
		}
	}
}

func Test_StartSecure(t *testing.T) {
	for i := 0; i < GOSESSION_TESTING_ITER; i++ {
		var id1 SessionId
		var id2 SessionId
		handler1 := func(w http.ResponseWriter, r *http.Request) {
			id1 = StartSecure(&w, r) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}
		handler2 := func(w http.ResponseWriter, r *http.Request) {
			id2 = StartSecure(&w, r) // calling the tested function
			io.WriteString(w, "<html><head><title>Title</title></head><body>Body</body></html>")
		}

		w1 := httptest.NewRecorder()
		r1 := httptest.NewRequest("GET", "/", nil)
		handler1(w1, r1)

		status := w1.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned status: %v", status)
		}

		cookies := w1.Result().Cookies()
		var cookie *http.Cookie
		for _, v := range cookies {
			cookie = v
		}
		w2 := httptest.NewRecorder()
		r2 := httptest.NewRequest("GET", "/", nil)
		r2.AddCookie(cookie)
		handler2(w2, r2)

		status = w2.Code
		// work check
		if status != http.StatusOK {
			t.Errorf("Handler returned status: %v", status)
		}

		// work check
		if id1 == id2 {
			t.Errorf("Server and client IDs are equal:\n server: %v\n client: %v\n", id1, id2)
		}
	}
}

// ----------------------
// Functions benchmarking
// ----------------------

func Benchmark_generateId(b *testing.B) {
	for i := 0; i < b.N; i++ {
		generateId() // calling the tested function
	}
}

func Benchmark_getOrSetCookie(b *testing.B) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		getOrSetCookie(&w, r) // calling the tested function
	}
	r := httptest.NewRequest("GET", "/", nil)
	w := httptest.NewRecorder()
	for i := 0; i < b.N; i++ {
		handler(w, r)
	}
}

func Benchmark_deleteCookie(b *testing.B) {
	// handler := func(w http.ResponseWriter, r *http.Request) {
	handler := func(w http.ResponseWriter) {
		deleteCookie(&w) // calling the tested function
	}
	w := httptest.NewRecorder()
	// r := httptest.NewRequest("GET", "/", nil)
	// cookie := &http.Cookie{
	// 	Name:   setingsSession.CookieName,
	// 	Value:  string(generateId()),
	// 	MaxAge: 0,
	// }
	// r.AddCookie(cookie)

	for i := 0; i < b.N; i++ {
		handler(w)
	}
}

func Benchmark_cleaningSessions(b *testing.B) {
	for i := 0; i < b.N; i++ {
		cleaningSessions() // calling the tested function
	}
}

func Benchmark_writeS(b *testing.B) {
	ses := internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       make(Session),
	}
	ses.data["name"] = "test value"
	id := generateId()

	for i := 0; i < b.N; i++ {
		id.writeS(ses) // calling the tested function
	}
}

func Benchmark_readS(b *testing.B) {
	ses := internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       make(Session),
	}
	ses.data["name"] = "test value"
	id := generateId()
	id.writeS(ses)

	for i := 0; i < b.N; i++ {
		id.readS() // calling the tested function
	}
}

func Benchmark_destroyS(b *testing.B) {
	ses := internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       make(Session),
	}
	ses.data["name"] = "test value"
	id := generateId()
	id.writeS(ses)

	for i := 0; i < b.N; i++ {
		id.destroyS() // calling the tested function
	}
}

func Benchmark_deleteS(b *testing.B) {
	ses := internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       make(Session),
	}
	ses.data["name"] = "test value"
	id := generateId()
	id.writeS(ses)

	for i := 0; i < b.N; i++ {
		id.deleteS("name") // calling the tested function
	}
}

func Benchmark_Set(b *testing.B) {
	rand.Seed(time.Now().Unix())
	id := generateId()
	data := make(Session)
	allSessions[id] = internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       data,
	}
	name := fmt.Sprintf("BenchName%d", rand.Intn(100))
	value := rand.Float64()

	for i := 0; i < b.N; i++ {
		id.Set(name, value) // calling the tested function
	}
}

func Benchmark_GetAll(b *testing.B) {
	rand.Seed(time.Now().Unix())
	id := generateId()
	data := make(Session)
	name := fmt.Sprintf("BenchName%d", rand.Intn(100))
	value := rand.Float64()
	data[name] = value
	allSessions[id] = internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       data,
	}

	for i := 0; i < b.N; i++ {
		id.GetAll() // calling the tested function
	}
}

func Benchmark_Get(b *testing.B) {
	rand.Seed(time.Now().Unix())
	id := generateId()
	data := make(Session)
	name := fmt.Sprintf("BenchName%d", rand.Intn(100))
	value := rand.Float64()
	data[name] = value
	allSessions[id] = internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       data,
	}

	for i := 0; i < b.N; i++ {
		id.Get(name) // calling the tested function
	}
}

func Benchmark_Destroy(b *testing.B) {
	w := httptest.NewRecorder()
	r := httptest.NewRequest("GET", "/", nil)
	id := generateId()
	cookie := &http.Cookie{
		Name:   setingsSession.CookieName,
		Value:  string(id),
		MaxAge: 0,
	}
	r.AddCookie(cookie)

	data := make(Session)
	name := fmt.Sprintf("BenchName%d", rand.Intn(100))
	value := rand.Float64()
	data[name] = value
	allSessions[id] = internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       data,
	}

	// handler := func(w http.ResponseWriter, r *http.Request) {
	handler := func(w http.ResponseWriter) {
		id.Destroy(&w) // calling the tested function
	}

	for i := 0; i < b.N; i++ {
		handler(w)
	}
}

func Benchmark_Remove(b *testing.B) {
	rand.Seed(time.Now().Unix())
	id := generateId()
	data := make(Session)
	name := fmt.Sprintf("BenchName%d", rand.Intn(100))
	value := rand.Float64()
	data[name] = value
	allSessions[id] = internalSession{
		expiration: time.Now().Unix() + setingsSession.Expiration,
		data:       data,
	}

	for i := 0; i < b.N; i++ {
		id.Remove(name) // calling the tested function
	}
}

func Benchmark_SetSetings(b *testing.B) {
	var test_setingsSession = GoSessionSetings{
		CookieName:    GOSESSION_COOKIE_NAME,
		Expiration:    GOSESSION_EXPIRATION,
		TimerCleaning: GOSESSION_TIMER_FOR_CLEANING,
	}
	for i := 0; i < b.N; i++ {
		SetSetings(test_setingsSession) // calling the tested function
	}
}

func Benchmark_Start(b *testing.B) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		Start(&w, r) // calling the tested function
	}
	r := httptest.NewRequest("GET", "/", nil)
	w := httptest.NewRecorder()
	for i := 0; i < b.N; i++ {
		handler(w, r)
	}
}

func Benchmark_StartSecure(b *testing.B) {
	handler := func(w http.ResponseWriter, r *http.Request) {
		StartSecure(&w, r) // calling the tested function
	}
	r := httptest.NewRequest("GET", "/", nil)
	w := httptest.NewRecorder()
	for i := 0; i < b.N; i++ {
		handler(w, r)
	}
}


================================================
FILE: pkg/examples/example1/go.mod
================================================
module example1

go 1.17

require github.com/Kwynto/gosession v0.2.4


================================================
FILE: pkg/examples/example1/go.sum
================================================
github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e h1:gNsAZ2trdqTriYD0H1YvhsiMzm8hjM3dd1zK64hEndM=
github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.1 h1:d0Dz1IBcjQ44nkAWkOz7hYEYrCfkyIjOIMnBhVy/GiE=
github.com/Kwynto/gosession v0.2.1/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.3 h1:8Ag0nXX0cCxrbFOFdCdPI9u46YtEEG/JFx1iHF+PH6I=
github.com/Kwynto/gosession v0.2.3/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.4 h1:SdK/0o1o88El3ALz/kFfZlrCfPBC6b6Czha6S5tb6vc=
github.com/Kwynto/gosession v0.2.4/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=


================================================
FILE: pkg/examples/example1/main.go
================================================
package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"net/http"

	"github.com/Kwynto/gosession"
)

func GetMd5(text string) string {
	h := md5.New()
	h.Write([]byte(text))
	return hex.EncodeToString(h.Sum(nil))
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	var html string = ""
	id := gosession.Start(&w, r)
	username := id.Get("username")

	if username != nil {
		html = `
		<html>
			<head>
				<title>Title</title>
			</head>
			<body>
				<p>
				You are authorized!<br>
				Your name is %s.<br>
				</p>
				<p>
				<a href="/logout">Logout?</a>
				</p>
				<p>
				<a href="/firstpage">First Page</a>
				</p>
				<p>
				<a href="/secondpage">Second Page</a>
				</p>
			</body>
		</html>
		`
		html = fmt.Sprintf(html, username)
	} else {
		html = `
		<html>
			<head>
				<title>Title</title>
			</head>
			<body>
				<p>
					<form action="/auth" method="post" class="form-horizontal">
						<input name="login" type="text" value="" placeholder="Login" required pattern="^[a-zA-Z0-9_-]+$">
						<input name="password" type="password" value="" placeholder="Password" required pattern="^[a-zA-Z0-9]+$">
						<button name="signin" type="submit">Auth button</button>
					</form>
				</p>
				<p>
					This is a test example of authorization on a web page.<br>
					Please enter any text as username and password
				</p>
			</body>
		</html>
		`
	}
	fmt.Fprint(w, html)
}

func authHandler(w http.ResponseWriter, r *http.Request) {
	username := r.FormValue("login")
	password := r.FormValue("password")

	id := gosession.Start(&w, r)

	if username != "" && password != "" {
		pasHash := GetMd5(password)
		id.Set("username", username)
		id.Set("hash", pasHash)
	}

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

func outHandler(w http.ResponseWriter, r *http.Request) {
	id := gosession.Start(&w, r)
	id.Destroy(&w)

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

func firstHandler(w http.ResponseWriter, r *http.Request) {
	id := gosession.Start(&w, r)
	ses := id.GetAll()
	username := ses["username"]
	pasHash := ses["hash"]

	html := `
		<html>
			<head>
				<title>Title</title>
			</head>
			<body>
				<p>
				You are authorized!<br>
				</p>
				<p>
				Your name is %s.<br>
				Hash password is %s <br>
				</p>
				<p>
				<a href="/">Home Page</a>
				</p>
			</body>
		</html>
		`
	html = fmt.Sprintf(html, username, pasHash)
	fmt.Fprint(w, html)
}

func secondHandler(w http.ResponseWriter, r *http.Request) {
	id := gosession.Start(&w, r)

	html := `
		<html>
			<head>
				<title>Title</title>
			</head>
			<body>
				<p>
				You are authorized!<br>
				</p>
				<p>
				Your session ID is: %s.<br>
				</p>
				<p>
				<a href="/">Home Page</a>
				</p>
			</body>
		</html>
		`
	html = fmt.Sprintf(html, id)
	fmt.Fprint(w, html)
}

func main() {
	port := ":8080"

	http.HandleFunc("/", homeHandler)
	http.HandleFunc("/auth", authHandler)
	http.HandleFunc("/logout", outHandler)
	http.HandleFunc("/firstpage", firstHandler)
	http.HandleFunc("/secondpage", secondHandler)

	http.ListenAndServe(port, nil)
}


================================================
FILE: pkg/examples/example2/go.mod
================================================
module example2

go 1.17

require github.com/Kwynto/gosession v0.2.4


================================================
FILE: pkg/examples/example2/go.sum
================================================
github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e h1:gNsAZ2trdqTriYD0H1YvhsiMzm8hjM3dd1zK64hEndM=
github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.1 h1:d0Dz1IBcjQ44nkAWkOz7hYEYrCfkyIjOIMnBhVy/GiE=
github.com/Kwynto/gosession v0.2.1/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.3 h1:8Ag0nXX0cCxrbFOFdCdPI9u46YtEEG/JFx1iHF+PH6I=
github.com/Kwynto/gosession v0.2.3/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.4 h1:SdK/0o1o88El3ALz/kFfZlrCfPBC6b6Czha6S5tb6vc=
github.com/Kwynto/gosession v0.2.4/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=


================================================
FILE: pkg/examples/example2/main.go
================================================
package main

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/Kwynto/gosession"
)

func homeHandler(w http.ResponseWriter, r *http.Request) {
	var html string
	header := `
	<html>
		<head>
			<title>Title</title>
		</head>
		<body>
			<p>
			<a href="/">Home Page</a><br>
			<a href="/firstpage">First Page</a><br>
			<a href="/secondpage">Second Page</a><br>
			<a href="/thirdpage">Third Page</a><br>
			<a href="/fourthpage">Fourth Page</a><br>
			<a href="/fifthpage">Fifth Page</a><br>
			</p>
			<p>
			Website browsing history:<br>
	`

	footer := `
			</p>
		</body>
	</html>
	`

	id := gosession.Start(&w, r)
	transitions := id.Get("transitions")

	if transitions == nil {
		transitions = ""
	}
	transitions = fmt.Sprint(transitions, " ", r.RequestURI)
	id.Set("transitions", transitions)

	msg := fmt.Sprintf("%v", transitions)
	msg = strings.ReplaceAll(msg, " ", "<br>")
	html = fmt.Sprint(header, msg, footer)

	fmt.Fprint(w, html)
}

func favHandler(w http.ResponseWriter, r *http.Request) {
	// dummy
}

func main() {
	port := ":8080"

	http.HandleFunc("/favicon.ico", favHandler)
	http.HandleFunc("/", homeHandler)

	http.ListenAndServe(port, nil)
}


================================================
FILE: pkg/examples/example3/cmd/web/handlers.go
================================================
package main

import (
	"fmt"
	"net/http"
	"strings"

	"github.com/Kwynto/gosession"
)

func (app *application) home(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		app.notFound(w)
		return
	}

	tD := &templateData{User: "", Hash: "", Cart: []string{""}, Transitions: []string{""}}

	id := gosession.StartSecure(&w, r)

	transitions := id.Get("transitions")
	if transitions == nil {
		transitions = ""
	}
	transitions = fmt.Sprint(transitions, " ", r.RequestURI)
	id.Set("transitions", transitions)
	tStr := fmt.Sprintf("%v", transitions)
	tStrs := strings.Split(tStr, " ")
	tD.Transitions = tStrs

	cart := id.Get("cart")
	if cart == nil {
		cart = ""
		id.Set("cart", fmt.Sprint(cart))
		tD.Cart = []string{"There's nothing here yet."}
	} else {
		sCart := fmt.Sprint(cart)
		prods := strings.Split(sCart, " ")
		tD.Cart = prods
	}

	username := id.Get("username")
	if username != nil {
		tD.User = fmt.Sprint(username)
		app.render(w, r, "homeauth.page.tmpl", tD)
	} else {
		app.render(w, r, "home.page.tmpl", tD)
	}
}

func (app *application) authPage(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		w.Header().Set("Allow", http.MethodPost)
		app.clientError(w, http.StatusMethodNotAllowed)
		return
	}

	username := r.FormValue("login")
	password := r.FormValue("password")

	id := gosession.StartSecure(&w, r)

	if username != "" && password != "" {
		pasHash := app.getMd5(password)
		id.Set("username", username)
		id.Set("hash", pasHash)
	}

	transitions := id.Get("transitions")
	if transitions == nil {
		transitions = ""
	}
	transitions = fmt.Sprint(transitions, " ", r.RequestURI)
	id.Set("transitions", transitions)

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

func (app *application) outPage(w http.ResponseWriter, r *http.Request) {
	id := gosession.StartSecure(&w, r)
	id.Remove("username")

	transitions := id.Get("transitions")
	if transitions == nil {
		transitions = ""
	}
	transitions = fmt.Sprint(transitions, " ", r.RequestURI)
	id.Set("transitions", transitions)

	http.Redirect(w, r, "/", http.StatusSeeOther)
}

func (app *application) buyPage(w http.ResponseWriter, r *http.Request) {
	tD := &templateData{User: "", Hash: "", Cart: []string{""}, Transitions: []string{""}}

	id := gosession.StartSecure(&w, r)

	transitions := id.Get("transitions")
	if transitions == nil {
		transitions = ""
	}
	transitions = fmt.Sprint(transitions, " ", r.RequestURI)
	id.Set("transitions", transitions)
	tStr := fmt.Sprintf("%v", transitions)
	tStrs := strings.Split(tStr, " ")
	tD.Transitions = tStrs

	cart := id.Get("cart")
	if cart == nil {
		cart = ""
	}
	sCart := app.addProduct(fmt.Sprint(cart), app.convertProduct(r.RequestURI))
	id.Set("cart", sCart)
	prods := strings.Split(sCart, " ")
	tD.Cart = prods

	username := id.Get("username")
	if username != nil {
		tD.User = fmt.Sprint(username)
		app.render(w, r, "homeauth.page.tmpl", tD)
	} else {
		app.render(w, r, "home.page.tmpl", tD)
	}
}


================================================
FILE: pkg/examples/example3/cmd/web/helpers.go
================================================
package main

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"net/http"
	"runtime/debug"
	"strconv"
	"strings"
)

func (app *application) getMd5(text string) string {
	h := md5.New()
	h.Write([]byte(text))
	return hex.EncodeToString(h.Sum(nil))
}

func (app *application) convertProduct(uri string) string {
	res := strings.Trim(uri, "/")
	res = strings.ToUpper(res)
	return res
}

func (app *application) addProduct(text string, plus string) string {
	var newText string = ""
	var newProd string = ""
	var isIt bool = false

	if text == "" {
		newText = fmt.Sprintf("%s=%d ", plus, 1)
		return newText
	}

	splitTest := strings.Split(text, " ")
	for _, val := range splitTest {
		if val != "" {
			splitVal := strings.Split(val, "=")
			prodName := splitVal[0]
			prodCount, _ := strconv.Atoi(splitVal[1])
			if prodName == plus {
				isIt = true
				prodCount += 1
				newProd = fmt.Sprintf("%s=%d", prodName, prodCount)
				newText = fmt.Sprintf("%s%s ", newText, newProd)
			} else {
				newText = fmt.Sprintf("%s%s ", newText, val)
			}
		}
	}

	if !isIt {
		newProd = fmt.Sprintf("%s=%d", plus, 1)
		newText = fmt.Sprintf("%s%s ", newText, newProd)
	}

	return newText
}

func (app *application) serverError(w http.ResponseWriter, err error) {
	trace := fmt.Sprintf("%s\n%s", err.Error(), debug.Stack())
	app.errorLog.Output(2, trace)
	http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
}

func (app *application) clientError(w http.ResponseWriter, status int) {
	http.Error(w, http.StatusText(status), status)
}

func (app *application) notFound(w http.ResponseWriter) {
	app.clientError(w, http.StatusNotFound)
}

func (app *application) render(w http.ResponseWriter, r *http.Request, name string, td *templateData) {
	// We extract the corresponding set of templates from the cache, depending on the page name
	ts, ok := app.templateCache[name]
	if !ok {
		app.serverError(w, fmt.Errorf("template %s not exist", name))
		return
	}

	// Render template files by passing dynamic data from the `td` variable.
	err := ts.Execute(w, td)
	if err != nil {
		app.serverError(w, err)
	}
}


================================================
FILE: pkg/examples/example3/cmd/web/main.go
================================================
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Creating an `application` structure to store the dependencies of the entire web application.
type application struct {
	errorLog      *log.Logger
	infoLog       *log.Logger
	templateCache map[string]*template.Template
}

// Structure for configuration
type Config struct {
	Addr      string
	StaticDir string
}

func main() {
	// Reading flags from the application launch bar.
	cfg := new(Config)
	flag.StringVar(&cfg.Addr, "addr", ":8080", "HTTP network address")
	flag.StringVar(&cfg.StaticDir, "static-dir", "./ui/static", "Path to static assets")
	flag.Parse()

	// Creating loggers
	infoLog := log.New(os.Stdout, "INFO\t", log.Ldate|log.Ltime)
	errorLog := log.New(os.Stderr, "ERROR\t", log.Ldate|log.Ltime|log.Lshortfile)

	// Initialize the template cache.
	templateCache, err := newTemplateCache("./ui/html/")
	if err != nil {
		errorLog.Fatal(err)
	}

	// Initialize the structure with the application dependencies.
	app := &application{
		errorLog:      errorLog,
		infoLog:       infoLog,
		templateCache: templateCache,
	}

	// Server structure with address, logger and routing
	srv := &http.Server{
		Addr:     cfg.Addr,
		ErrorLog: errorLog,
		Handler:  app.routes(),
	}

	// Starting the server
	app.infoLog.Printf("Start server: %s", cfg.Addr)
	err = srv.ListenAndServe()
	app.errorLog.Fatal(err)
}


================================================
FILE: pkg/examples/example3/cmd/web/routes.go
================================================
package main

import (
	"net/http"
	"path/filepath"
)

type neuteredFileSystem struct {
	fs http.FileSystem
}

// Blocking direct access to the file system
func (nfs neuteredFileSystem) Open(path string) (http.File, error) {
	f, err := nfs.fs.Open(path)
	if err != nil {
		return nil, err
	}

	s, _ := f.Stat()
	if s.IsDir() {
		index := filepath.Join(path, "index.html")
		if _, err := nfs.fs.Open(index); err != nil {
			closeErr := f.Close()
			if closeErr != nil {
				return nil, closeErr
			}

			return nil, err
		}
	}

	return f, nil
}

func (app *application) routes() *http.ServeMux {
	// Routes
	mux := http.NewServeMux()
	mux.HandleFunc("/", app.home)
	mux.HandleFunc("/auth", app.authPage)
	mux.HandleFunc("/logout", app.outPage)
	mux.HandleFunc("/product1", app.buyPage)
	mux.HandleFunc("/product2", app.buyPage)
	mux.HandleFunc("/product3", app.buyPage)

	fileServer := http.FileServer(neuteredFileSystem{http.Dir("./ui/static")})
	mux.Handle("/static", http.NotFoundHandler())
	mux.Handle("/static/", http.StripPrefix("/static", fileServer))

	return mux
}


================================================
FILE: pkg/examples/example3/cmd/web/templates.go
================================================
package main

import (
	"html/template"
	"path/filepath"
)

// Structure for the data template
type templateData struct {
	User        string
	Hash        string
	Cart        []string
	Transitions []string
}

func newTemplateCache(dir string) (map[string]*template.Template, error) {
	cache := map[string]*template.Template{}

	// We use the filepath.Glob function to get a slice of all file paths with the extension '.page.tmpl'.
	pages, err := filepath.Glob(filepath.Join(dir, "*.page.tmpl"))
	if err != nil {
		return nil, err
	}

	// We iterate through the template file from each page.
	for _, page := range pages {
		// Extracting the final file name
		name := filepath.Base(page)

		// Processing the iterated template file.
		ts, err := template.ParseFiles(page)
		if err != nil {
			return nil, err
		}

		// We use the ParseGlob method to add all the wireframe templates.
		ts, err = ts.ParseGlob(filepath.Join(dir, "*.layout.tmpl"))
		if err != nil {
			return nil, err
		}

		// We use the ParseGlob method to add all auxiliary templates.
		ts, err = ts.ParseGlob(filepath.Join(dir, "*.partial.tmpl"))
		if err != nil {
			return nil, err
		}

		// Adding the resulting set of templates to the cache using the page name
		cache[name] = ts
	}

	// We return the received map.
	return cache, nil
}


================================================
FILE: pkg/examples/example3/go.mod
================================================
module example3

go 1.17

require github.com/Kwynto/gosession v0.2.4


================================================
FILE: pkg/examples/example3/go.sum
================================================
github.com/Kwynto/gosession v0.2.1 h1:d0Dz1IBcjQ44nkAWkOz7hYEYrCfkyIjOIMnBhVy/GiE=
github.com/Kwynto/gosession v0.2.1/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.3 h1:8Ag0nXX0cCxrbFOFdCdPI9u46YtEEG/JFx1iHF+PH6I=
github.com/Kwynto/gosession v0.2.3/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=
github.com/Kwynto/gosession v0.2.4 h1:SdK/0o1o88El3ALz/kFfZlrCfPBC6b6Czha6S5tb6vc=
github.com/Kwynto/gosession v0.2.4/go.mod h1:t9ebCczcC/w08whDLwShIZ59finO9EyRkiQf5B31m90=


================================================
FILE: pkg/examples/example3/ui/html/base.layout.tmpl
================================================
{{define "base"}}
<!doctype html>
<html lang='en'>
<head>
    <meta charset='utf-8'>
    <title>{{template "title" .}}</title>
    <link rel='stylesheet' href='/static/css/main.css'>
    <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Ubuntu+Mono:400,700'>
</head>
<body>
    <header>
        <h1><a href='/'>Home Page</a></h1>
    </header>
    <nav>
        <a href='/'>Home Page</a>
    </nav>
    <main>
        {{template "main" .}}
    </main>
    {{template "footer" .}}
    <script src="/static/js/main.js" type="text/javascript"></script>
</body>
</html>
{{end}}

================================================
FILE: pkg/examples/example3/ui/html/footer.partial.tmpl
================================================
{{define "footer"}}
<footer>This is the third example of a <strong>GoLang</strong> site using <strong>GoSession</strong>.</footer>
{{end}}

================================================
FILE: pkg/examples/example3/ui/html/home.page.tmpl
================================================
{{template "base" .}}

{{define "title"}}Home Page{{end}}

{{define "main"}}
	<table>
		<tr>
			<td rowspan="2" valign="top">
				<p>
					<h2>Authorization</h2>
					<form action="/auth" method="post" class="form-horizontal">
						<input name="login" type="text" value="" placeholder="Login" required pattern="^[a-zA-Z0-9_-]+$">
						<input name="password" type="password" value="" placeholder="Password" required pattern="^[a-zA-Z0-9]+$">
						<button name="signin" type="submit">Auth button</button>
					</form>
					<br><br>
				</p>
				<p>
					<h2>Links:</h2>
					<a href="/product1">Buy Product No. 1</a><br><br>
					<a href="/product2">Buy Product No. 2</a><br><br>
					<a href="/product3">Buy Product No. 3</a><br><br>
				</p>
			</td>
			<td width="250px">
				<p>
					<h2>Shopping cart</h2>
					{{ range $key, $pr := .Cart }}
						{{ $pr }}<br>
					{{end}}
				</p>
			</td>
		</tr>
		<tr>
			<td>
				<p>
					<h2>Browsing history:</h2>
					{{ range $key, $tr := .Transitions }}
						{{ $tr }}<br>
					{{end}}
				</p>
			</td>
		</tr>
	</table>
{{end}}

================================================
FILE: pkg/examples/example3/ui/html/homeauth.page.tmpl
================================================
{{template "base" .}}

{{define "title"}}Home Page{{end}}

{{define "main"}}
	<table>
		<tr>
			<td rowspan="2" valign="top">
				<p>
					<h3>You are logged in as: </h3>{{.User}} <a href="/logout">Log Out</a><br><br>
				</p>
				<p>
					<h2>Links:</h2>
					<a href="/product1">Buy Product No. 1</a><br><br>
					<a href="/product2">Buy Product No. 2</a><br><br>
					<a href="/product3">Buy Product No. 3</a><br><br>
				</p>
			</td>
			<td width="250px">
				<p>
					<h2>Shopping cart</h2>
					{{ range $key, $pr := .Cart }}
						{{ $pr }}<br>
					{{end}}
				</p>
			</td>
		</tr>
		<tr>
			<td>
				<p>
					<h2>Browsing history:</h2>
					{{ range $key, $tr := .Transitions }}
						{{ $tr }}<br>
					{{end}}
				</p>
			</td>
		</tr>
	</table>
{{end}}

================================================
FILE: pkg/examples/example3/ui/static/css/main.css
================================================
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    font-size: 18px;
    font-family: "Ubuntu Mono", monospace;
}

html, body {
    height: 100%;
}

body {
    line-height: 1.5;
    background-color: #F1F3F6;
    color: #34495E;
    overflow-y: scroll;
}

header, nav, main, footer {
    padding: 2px calc((100% - 800px) / 2) 0;
}

main {
    margin-top: 54px;
    margin-bottom: 54px;
    min-height: calc(100vh - 345px);
    overflow: auto;
}

h1 a {
    font-size: 36px;
    font-weight: bold;
    background-image: url("/static/img/logo.png");
    background-repeat: no-repeat;
    background-position: 0px 0px;
    height: 36px;
    padding-left: 50px;
    position: relative;
}

h1 a:hover {
    text-decoration: none;
    color: #34495E;
}

h2 {
    font-size: 22px;
    margin-bottom: 36px;
    position: relative;
    top: -9px;
}

a {
    color: #62CB31;
    text-decoration: none;
}

a:hover {
    color: #4EB722;
    text-decoration: underline;
}

textarea, input:not([type="submit"]) {
    font-size: 18px;
    font-family: "Ubuntu Mono", monospace;
}

header {
    background-image: -webkit-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%);
    background-image: -moz-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%);
    background-image: -ms-linear-gradient(left, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%);
    background-image: linear-gradient(to right, #34495e, #34495e 25%, #9b59b6 25%, #9b59b6 35%, #3498db 35%, #3498db 45%, #62cb31 45%, #62cb31 55%, #ffb606 55%, #ffb606 65%, #e67e22 65%, #e67e22 75%, #e74c3c 85%, #e74c3c 85%, #c0392b 85%, #c0392b 100%);
    background-size: 100% 6px;
    background-repeat: no-repeat;
    border-bottom: 1px solid #E4E5E7;
    overflow: auto;
    padding-top: 33px;
    padding-bottom: 27px;
    text-align: center;
}

header a {
    color: #34495E;
    text-decoration: none;
}

nav {
    border-bottom: 1px solid #E4E5E7;
    padding-top: 17px;
    padding-bottom: 15px;
    background: #F7F9FA;
    height: 60px;
    color: #6A6C6F;
}

nav a {
    margin-right: 1.5em;
    display: inline-block;
}

nav form {
    display: inline-block;
    margin-left: 1.5em;
}

nav div {
    width: 50%;
    float: left;
}

nav div:last-child {
    text-align: right;
}

nav div:last-child a {
    margin-left: 1.5em;
    margin-right: 0;
}

nav a.live {
    color: #34495E;
    cursor: default;
}

nav a.live:hover {
    text-decoration: none;
}

nav a.live:after {
    content: '';
    display: block;
    position: relative;
    left: calc(50% - 7px);
    top: 9px;
    width: 14px;
    height: 14px;
    background: #F7F9FA;
    border-left: 1px solid #E4E5E7;
    border-bottom: 1px solid #E4E5E7;
    -moz-transform: rotate(45deg);
    -webkit-transform: rotate(-45deg);
}

form div {
    margin-bottom: 18px;
}

form div:last-child {
    border-top: 1px dashed #E4E5E7;
}

form input[type="radio"] {
    position: relative;
    top: 2px;
    margin-left: 18px;
}

form input[type="text"], form input[type="password"], form input[type="email"] {
    padding: 0.75em 18px;
    width: 100%;
}

form input[type=text], form input[type="password"], form input[type="email"], textarea {
    color: #6A6C6F;
    background: #FFFFFF;
    border: 1px solid #E4E5E7;
    border-radius: 3px;
}

form label {
    display: inline-block;
    margin-bottom: 9px;
}

.error {
    color: #C0392B;
    font-weight: bold;
    display: block;
}

.error + textarea, .error + input {
    border-color: #C0392B !important;
    border-width: 2px !important;
}

textarea {
    padding: 18px;
    width: 100%;
    height: 266px;
}

button {
    background-color: #4CAF50;
    border: none;
    color: white;
    padding: 15px 32px;
    text-align: center;
    text-decoration: none;
    display: inline-block;
    font-size: 16px;
    margin: 4px 2px;
    cursor: pointer;
    width: 100%;
}

button:hover {
    background-color: #5865f4;
    color: white;
}

.snippet {
    background-color: #FFFFFF;
    border: 1px solid #E4E5E7;
    border-radius: 3px;
}

.snippet pre {
    padding: 18px;
    border-top: 1px solid #E4E5E7;
    border-bottom: 1px solid #E4E5E7;
}

.snippet .metadata {
    background-color: #F7F9FA;
    color: #6A6C6F;
    padding: 0.75em 18px;
    overflow: auto;
}

.snippet .metadata span {
    float: right;
}

.snippet .metadata strong {
    color: #34495E;
}

.snippet .metadata time {
    display: inline-block;
}

.snippet .metadata time:first-child {
    float: left;
}

.snippet .metadata time:last-child {
    float: right;
}

div.flash {
    color: #FFFFFF;
    font-weight: bold;
    background-color: #34495E;
    padding: 18px;
    margin-bottom: 36px;
    text-align: center;
}

div.error {
    color: #FFFFFF;
    background-color: #C0392B;
    padding: 18px;
    margin-bottom: 36px;
    font-weight: bold;
    text-align: center;
}

table {
    background: white;
    border: 1px solid #E4E5E7;
    border-collapse: collapse;
    width: 100%;
}

td, th {
    text-align: left;
    padding: 9px 18px;
}

th:last-child, td:last-child {
    text-align: right;
    color: #6A6C6F;
}

tr {
    border-bottom: 1px solid #E4E5E7;
}

tr:nth-child(2n) {
    background-color: #F7F9FA;
}

footer {
    border-top: 1px solid #E4E5E7;
    padding-top: 17px;
    padding-bottom: 15px;
    background: #F7F9FA;
    height: 60px;
    color: #6A6C6F;
    text-align: center;
}


================================================
FILE: pkg/examples/example3/ui/static/js/main.js
================================================
var navLinks = document.querySelectorAll("nav a");
for (var i = 0; i < navLinks.length; i++) {
	var link = navLinks[i]
	if (link.getAttribute('href') == window.location.pathname) {
		link.classList.add("live");
		break;
	}
}
Download .txt
gitextract_1luo0k9u/

├── .github/
│   └── workflows/
│       └── go.yaml
├── .gitignore
├── LICENSE
├── README.md
├── go.mod
├── gosession.go
├── gosession_test.go
└── pkg/
    └── examples/
        ├── example1/
        │   ├── go.mod
        │   ├── go.sum
        │   └── main.go
        ├── example2/
        │   ├── go.mod
        │   ├── go.sum
        │   └── main.go
        └── example3/
            ├── cmd/
            │   └── web/
            │       ├── handlers.go
            │       ├── helpers.go
            │       ├── main.go
            │       ├── routes.go
            │       └── templates.go
            ├── go.mod
            ├── go.sum
            └── ui/
                ├── html/
                │   ├── base.layout.tmpl
                │   ├── footer.partial.tmpl
                │   ├── home.page.tmpl
                │   └── homeauth.page.tmpl
                └── static/
                    ├── css/
                    │   └── main.css
                    └── js/
                        └── main.js
Download .txt
SYMBOL INDEX (87 symbols across 9 files)

FILE: gosession.go
  constant GOSESSION_COOKIE_NAME (line 18) | GOSESSION_COOKIE_NAME        string        = "SessionId"
  constant GOSESSION_EXPIRATION (line 19) | GOSESSION_EXPIRATION         int64         = 43_200
  constant GOSESSION_TIMER_FOR_CLEANING (line 20) | GOSESSION_TIMER_FOR_CLEANING time.Duration = time.Hour
  type SessionId (line 24) | type SessionId
    method writeS (line 105) | func (id SessionId) writeS(iSes internalSession) {
    method readS (line 112) | func (id SessionId) readS() (internalSession, bool) {
    method destroyS (line 123) | func (id SessionId) destroyS() {
    method deleteS (line 131) | func (id SessionId) deleteS(name string) {
    method Set (line 144) | func (id SessionId) Set(name string, value interface{}) {
    method GetAll (line 153) | func (id SessionId) GetAll() Session {
    method Get (line 160) | func (id SessionId) Get(name string) interface{} {
    method Destroy (line 166) | func (id SessionId) Destroy(w *http.ResponseWriter) {
    method Remove (line 172) | func (id SessionId) Remove(name string) {
  type Session (line 27) | type Session
  type internalSession (line 30) | type internalSession struct
  type serverSessions (line 36) | type serverSessions
  type GoSessionSetings (line 39) | type GoSessionSetings struct
  function generateId (line 58) | func generateId() SessionId {
  function getOrSetCookie (line 65) | func getOrSetCookie(w *http.ResponseWriter, r *http.Request) SessionId {
  function deleteCookie (line 81) | func deleteCookie(w *http.ResponseWriter) {
  function cleaningSessions (line 91) | func cleaningSessions() {
  function SetSetings (line 178) | func SetSetings(setings GoSessionSetings) {
  function Start (line 184) | func Start(w *http.ResponseWriter, r *http.Request) SessionId {
  function StartSecure (line 198) | func StartSecure(w *http.ResponseWriter, r *http.Request) SessionId {
  function init (line 224) | func init() {

FILE: gosession_test.go
  constant GOSESSION_TESTING_ITER (line 18) | GOSESSION_TESTING_ITER int = 100
  function Test_generateId (line 25) | func Test_generateId(t *testing.T) {
  function Test_getOrSetCookie (line 47) | func Test_getOrSetCookie(t *testing.T) {
  function Test_deleteCookie (line 108) | func Test_deleteCookie(t *testing.T) {
  function Test_cleaningSessions (line 146) | func Test_cleaningSessions(t *testing.T) {
  function Test_writeS (line 180) | func Test_writeS(t *testing.T) {
  function Test_readS (line 194) | func Test_readS(t *testing.T) {
  function Test_destroyS (line 215) | func Test_destroyS(t *testing.T) {
  function Test_deleteS (line 231) | func Test_deleteS(t *testing.T) {
  function Test_Set (line 250) | func Test_Set(t *testing.T) {
  function Test_GetAll (line 281) | func Test_GetAll(t *testing.T) {
  function Test_Get (line 319) | func Test_Get(t *testing.T) {
  function Test_Destroy (line 353) | func Test_Destroy(t *testing.T) {
  function Test_Remove (line 413) | func Test_Remove(t *testing.T) {
  function Test_SetSetings (line 447) | func Test_SetSetings(t *testing.T) {
  function Test_Start (line 473) | func Test_Start(t *testing.T) {
  function Test_StartSecure (line 519) | func Test_StartSecure(t *testing.T) {
  function Benchmark_generateId (line 569) | func Benchmark_generateId(b *testing.B) {
  function Benchmark_getOrSetCookie (line 575) | func Benchmark_getOrSetCookie(b *testing.B) {
  function Benchmark_deleteCookie (line 586) | func Benchmark_deleteCookie(b *testing.B) {
  function Benchmark_cleaningSessions (line 605) | func Benchmark_cleaningSessions(b *testing.B) {
  function Benchmark_writeS (line 611) | func Benchmark_writeS(b *testing.B) {
  function Benchmark_readS (line 624) | func Benchmark_readS(b *testing.B) {
  function Benchmark_destroyS (line 638) | func Benchmark_destroyS(b *testing.B) {
  function Benchmark_deleteS (line 652) | func Benchmark_deleteS(b *testing.B) {
  function Benchmark_Set (line 666) | func Benchmark_Set(b *testing.B) {
  function Benchmark_GetAll (line 682) | func Benchmark_GetAll(b *testing.B) {
  function Benchmark_Get (line 699) | func Benchmark_Get(b *testing.B) {
  function Benchmark_Destroy (line 716) | func Benchmark_Destroy(b *testing.B) {
  function Benchmark_Remove (line 746) | func Benchmark_Remove(b *testing.B) {
  function Benchmark_SetSetings (line 763) | func Benchmark_SetSetings(b *testing.B) {
  function Benchmark_Start (line 774) | func Benchmark_Start(b *testing.B) {
  function Benchmark_StartSecure (line 785) | func Benchmark_StartSecure(b *testing.B) {

FILE: pkg/examples/example1/main.go
  function GetMd5 (line 12) | func GetMd5(text string) string {
  function homeHandler (line 18) | func homeHandler(w http.ResponseWriter, r *http.Request) {
  function authHandler (line 72) | func authHandler(w http.ResponseWriter, r *http.Request) {
  function outHandler (line 87) | func outHandler(w http.ResponseWriter, r *http.Request) {
  function firstHandler (line 94) | func firstHandler(w http.ResponseWriter, r *http.Request) {
  function secondHandler (line 123) | func secondHandler(w http.ResponseWriter, r *http.Request) {
  function main (line 148) | func main() {

FILE: pkg/examples/example2/main.go
  function homeHandler (line 11) | func homeHandler(w http.ResponseWriter, r *http.Request) {
  function favHandler (line 53) | func favHandler(w http.ResponseWriter, r *http.Request) {
  function main (line 57) | func main() {

FILE: pkg/examples/example3/cmd/web/handlers.go
  method home (line 11) | func (app *application) home(w http.ResponseWriter, r *http.Request) {
  method authPage (line 51) | func (app *application) authPage(w http.ResponseWriter, r *http.Request) {
  method outPage (line 79) | func (app *application) outPage(w http.ResponseWriter, r *http.Request) {
  method buyPage (line 93) | func (app *application) buyPage(w http.ResponseWriter, r *http.Request) {

FILE: pkg/examples/example3/cmd/web/helpers.go
  method getMd5 (line 13) | func (app *application) getMd5(text string) string {
  method convertProduct (line 19) | func (app *application) convertProduct(uri string) string {
  method addProduct (line 25) | func (app *application) addProduct(text string, plus string) string {
  method serverError (line 60) | func (app *application) serverError(w http.ResponseWriter, err error) {
  method clientError (line 66) | func (app *application) clientError(w http.ResponseWriter, status int) {
  method notFound (line 70) | func (app *application) notFound(w http.ResponseWriter) {
  method render (line 74) | func (app *application) render(w http.ResponseWriter, r *http.Request, n...

FILE: pkg/examples/example3/cmd/web/main.go
  type application (line 12) | type application struct
  type Config (line 19) | type Config struct
  function main (line 24) | func main() {

FILE: pkg/examples/example3/cmd/web/routes.go
  type neuteredFileSystem (line 8) | type neuteredFileSystem struct
    method Open (line 13) | func (nfs neuteredFileSystem) Open(path string) (http.File, error) {
  method routes (line 35) | func (app *application) routes() *http.ServeMux {

FILE: pkg/examples/example3/cmd/web/templates.go
  type templateData (line 9) | type templateData struct
  function newTemplateCache (line 16) | func newTemplateCache(dir string) (map[string]*template.Template, error) {
Condensed preview — 26 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (71K chars).
[
  {
    "path": ".github/workflows/go.yaml",
    "chars": 767,
    "preview": "# This workflow will build a golang project\n# For more information see: https://docs.github.com/en/actions/automating-bu"
  },
  {
    "path": ".gitignore",
    "chars": 158,
    "preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n# Test binary, built with `go test -c`\n*.test\n\n# Ou"
  },
  {
    "path": "LICENSE",
    "chars": 1094,
    "preview": "MIT License\n\nCopyright (c) 2022 Constantine Zavezeon <kwynto@mail.ru>\n\n\nPermission is hereby granted, free of charge, to"
  },
  {
    "path": "README.md",
    "chars": 11929,
    "preview": "# GoSession\nThis is quick session for net/http in GoLang.  \nThis package is perhaps the best implementation of the sessi"
  },
  {
    "path": "go.mod",
    "chars": 44,
    "preview": "module github.com/Kwynto/gosession\n\ngo 1.17\n"
  },
  {
    "path": "gosession.go",
    "chars": 6557,
    "preview": "// This is quick session for net/http in golang.\n// This package is perhaps the best implementation of the session mecha"
  },
  {
    "path": "gosession_test.go",
    "chars": 18833,
    "preview": "package gosession\n\n// --------------------------------------------------------\n// Copyright (c) 2022 Constantine Zavezeo"
  },
  {
    "path": "pkg/examples/example1/go.mod",
    "chars": 69,
    "preview": "module example1\n\ngo 1.17\n\nrequire github.com/Kwynto/gosession v0.2.4\n"
  },
  {
    "path": "pkg/examples/example1/go.sum",
    "chars": 748,
    "preview": "github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e h1:gNsAZ2trdqTriYD0H1YvhsiMzm8hjM3dd1zK64hEndM=\ngithub.co"
  },
  {
    "path": "pkg/examples/example1/main.go",
    "chars": 3063,
    "preview": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/Kwynto/gosession\"\n)\n\nfunc GetMd5(t"
  },
  {
    "path": "pkg/examples/example2/go.mod",
    "chars": 69,
    "preview": "module example2\n\ngo 1.17\n\nrequire github.com/Kwynto/gosession v0.2.4\n"
  },
  {
    "path": "pkg/examples/example2/go.sum",
    "chars": 748,
    "preview": "github.com/Kwynto/gosession v0.0.0-20220620140922-d2e7b2c35b8e h1:gNsAZ2trdqTriYD0H1YvhsiMzm8hjM3dd1zK64hEndM=\ngithub.co"
  },
  {
    "path": "pkg/examples/example2/main.go",
    "chars": 1169,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/Kwynto/gosession\"\n)\n\nfunc homeHandler(w http.Response"
  },
  {
    "path": "pkg/examples/example3/cmd/web/handlers.go",
    "chars": 2974,
    "preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"strings\"\n\n\t\"github.com/Kwynto/gosession\"\n)\n\nfunc (app *application) home(w h"
  },
  {
    "path": "pkg/examples/example3/cmd/web/helpers.go",
    "chars": 2133,
    "preview": "package main\n\nimport (\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"runtime/debug\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc ("
  },
  {
    "path": "pkg/examples/example3/cmd/web/main.go",
    "chars": 1394,
    "preview": "package main\n\nimport (\n\t\"flag\"\n\t\"html/template\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n)\n\n// Creating an `application` structure to st"
  },
  {
    "path": "pkg/examples/example3/cmd/web/routes.go",
    "chars": 1073,
    "preview": "package main\n\nimport (\n\t\"net/http\"\n\t\"path/filepath\"\n)\n\ntype neuteredFileSystem struct {\n\tfs http.FileSystem\n}\n\n// Blocki"
  },
  {
    "path": "pkg/examples/example3/cmd/web/templates.go",
    "chars": 1308,
    "preview": "package main\n\nimport (\n\t\"html/template\"\n\t\"path/filepath\"\n)\n\n// Structure for the data template\ntype templateData struct "
  },
  {
    "path": "pkg/examples/example3/go.mod",
    "chars": 69,
    "preview": "module example3\n\ngo 1.17\n\nrequire github.com/Kwynto/gosession v0.2.4\n"
  },
  {
    "path": "pkg/examples/example3/go.sum",
    "chars": 519,
    "preview": "github.com/Kwynto/gosession v0.2.1 h1:d0Dz1IBcjQ44nkAWkOz7hYEYrCfkyIjOIMnBhVy/GiE=\ngithub.com/Kwynto/gosession v0.2.1/go"
  },
  {
    "path": "pkg/examples/example3/ui/html/base.layout.tmpl",
    "chars": 592,
    "preview": "{{define \"base\"}}\n<!doctype html>\n<html lang='en'>\n<head>\n    <meta charset='utf-8'>\n    <title>{{template \"title\" .}}</"
  },
  {
    "path": "pkg/examples/example3/ui/html/footer.partial.tmpl",
    "chars": 138,
    "preview": "{{define \"footer\"}}\n<footer>This is the third example of a <strong>GoLang</strong> site using <strong>GoSession</strong>"
  },
  {
    "path": "pkg/examples/example3/ui/html/home.page.tmpl",
    "chars": 1081,
    "preview": "{{template \"base\" .}}\n\n{{define \"title\"}}Home Page{{end}}\n\n{{define \"main\"}}\n\t<table>\n\t\t<tr>\n\t\t\t<td rowspan=\"2\" valign=\""
  },
  {
    "path": "pkg/examples/example3/ui/html/homeauth.page.tmpl",
    "chars": 766,
    "preview": "{{template \"base\" .}}\n\n{{define \"title\"}}Home Page{{end}}\n\n{{define \"main\"}}\n\t<table>\n\t\t<tr>\n\t\t\t<td rowspan=\"2\" valign=\""
  },
  {
    "path": "pkg/examples/example3/ui/static/css/main.css",
    "chars": 5863,
    "preview": "* {\n    box-sizing: border-box;\n    margin: 0;\n    padding: 0;\n    font-size: 18px;\n    font-family: \"Ubuntu Mono\", mono"
  },
  {
    "path": "pkg/examples/example3/ui/static/js/main.js",
    "chars": 224,
    "preview": "var navLinks = document.querySelectorAll(\"nav a\");\nfor (var i = 0; i < navLinks.length; i++) {\n\tvar link = navLinks[i]\n\t"
  }
]

About this extraction

This page contains the full source code of the Kwynto/gosession GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 26 files (61.9 KB), approximately 19.5k tokens, and a symbol index with 87 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!