{"id":37186566,"url":"https://github.com/corestoreio/caddy-esi","last_synced_at":"2026-01-14T21:38:22.518Z","repository":{"id":57522426,"uuid":"66066012","full_name":"corestoreio/caddy-esi","owner":"corestoreio","description":"Middleware for Caddy Server integrating ESI (edge side includes) tags with parallel loading. Able to connect to HTTP/S/2, Memcache, Redis, shell scripts, gRPC and SQL backends 🐜🐜🐜","archived":false,"fork":false,"pushed_at":"2025-12-17T18:23:29.000Z","size":768,"stargazers_count":31,"open_issues_count":1,"forks_count":8,"subscribers_count":8,"default_branch":"master","last_synced_at":"2026-01-13T19:55:25.130Z","etag":null,"topics":["caddy","caddy-server","caddyserver","esi","esi-tags","grpc","redis","varnish","webserver"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/corestoreio.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2016-08-19T08:22:43.000Z","updated_at":"2025-12-17T18:23:34.000Z","dependencies_parsed_at":"2022-08-26T03:51:27.149Z","dependency_job_id":null,"html_url":"https://github.com/corestoreio/caddy-esi","commit_stats":null,"previous_names":["schumacherfm/caddyesi"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/corestoreio/caddy-esi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corestoreio%2Fcaddy-esi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corestoreio%2Fcaddy-esi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corestoreio%2Fcaddy-esi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corestoreio%2Fcaddy-esi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/corestoreio","download_url":"https://codeload.github.com/corestoreio/caddy-esi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/corestoreio%2Fcaddy-esi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28435812,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T21:32:52.117Z","status":"ssl_error","status_checked_at":"2026-01-14T21:32:33.442Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caddy","caddy-server","caddyserver","esi","esi-tags","grpc","redis","varnish","webserver"],"created_at":"2026-01-14T21:38:21.637Z","updated_at":"2026-01-14T21:38:22.502Z","avatar_url":"https://github.com/corestoreio.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ESI Tags for Caddy Server (Alpha, WIP\n)\n\nThis plugin implements partial ESI [Edge Side Includes](https://en.wikipedia.org/wiki/Edge_Side_Includes) \nsupport for the [Caddy Webserver](https://caddyserver.com) to allow data\nretrieving from heterogeneous backends aka. micro services.\n\n### Test Users Wanted!\n\nThis plugin has the pre-beta status and we need some users who tests it with\nvarious other middlewares on either their test server or even in production. The\nplugin has been running currently for a couple of weeks on\n[https://cyrillschumacher.com](https://cyrillschumacher.com/projects/2017-03-04-edge-side-includes-with-caddy/).\nSo far it runs smoothly. Please test it and report bugs in the issue tracker.\n\nThanks!\n\n[![Build Status](https://travis-ci.org/corestoreio/caddy-esi.svg?branch=master)](https://travis-ci.org/corestoreio/caddy-esi)\n\n#### Some features:\n\n- Query data from HTTP, HTTPS, HTTP2, gRPC, Redis, Memcache and soon SQL.\nDefault implementation: HTTP/S/2.\n- Multiple incoming requests trigger only one single parsing of the ESI tags per\npage\n- Querying multiple backend server parallel and concurrent.\n- Coalesce multiple incoming requests into one single request to a backend\nserver\n- Forwarding and returning (todo) of HTTP headers from backend servers\n- Query multiple backend servers sequentially as a fall back mechanism\n- Query multiple backend servers parallel and use the first returned result and\ndiscard other responses, an obvious race condition. (todo)\n- Support for NoSQL Server to query a key and simply display its value\n- Variables support based on Server, Cookie, Header or GET/POST form parameters\n- Error handling and fail over. Either display a text from a string or a static\nfile content when a backend server is unavailable.\n- If an HTTP/S backend request takes longer than the specified timeout, flip the\nsource URL into an XHR request or an HTTP2 push. (todo)\n- No full ESI support, if desired use a scripting language ;-)\n- Supports Go \u003e= 1.8\n\n**Warning:** Project still in beta phase and to enable more backend resources\nyou need to buy a monthly recurring Enterprise maintenance support (Coming\nsoon!)\n\n## High level overview\n\n![Architectural overview](caddy-esi-archi.png)\n\nAs the above sequence diagram shows, the output of the initial byte starts only\nthen, when all data from the backend resources has been received. This enables\nus to calculate the correct `Content-Length` header and also allows to return\nheaders from the backend to the client. So [time to first byte \"TTFB\"](https://en.wikipedia.org/wiki/Time_To_First_Byte) \ndepends on the slowest backend resource.\n\nFuture versions of CaddyESI provides the additional option of enabling\n`Transfer-Encoding: chunked` to start immediately the output and then waiting\nfor all backend resources when the first ESI tag occurs in the page.\n\n## Plugin configuration (optional)\n\n```\nhttps://cyrillschumacher.local:2718 {\n    ...\n    other caddy directives\n    ...\n    esi [/path_optional] {\n        [timeout 5ms|100us|1m|...]\n        [ttl 5ms|100us|1m|...]\n        [max_body_size 500kib|5MB|10GB|2EB|etc]\n        [page_id_source [host,path,ip, etc]]\n        [allowed_methods [GET,POST,etc]]\n        [cmd_header_name [X-What-Ever]]\n        [cache redis://localhost:6379/0]\n        [cache redis://localhost:6380/0]\n        [cache memcache://localhost:11211/2]\n        [cache inmemory]\n        [on_error (filename|\"any text\")]\n        [log_file (filename|stdout|stderr)]\n        [log_level (fatal|info|debug)]\n        [resources path/to/url_configrations.(xml|json)]\n    }\n}\n```\n\nMost of the **global optional configuration values** can be overwritten with a\ndifferent value in a single ESI tag.\n\n`esi` defines the namespace in the Caddy configuration file. Reserved keys are:\n\n| Config Name |  Default | Support in ESI tag | Description |\n| ----------- |  ------- | ----------- |  ----------- |\n| `[path]`   | `/`    | n/a | Under this path all pages gets parsed for ESI tags. Default path sets to slash. |\n| `timeout`   | 20s    | Yes | Time when a request to a resource should be canceled. [time.Duration](https://golang.org/pkg/time/#Duration) |\n| `ttl`      | disabled  | Yes | Time-to-live value in the NoSQL cache for data returned from the backend resources. |\n| `max_body_size` | 5MB       | Yes |  Limits the size of the returned body from a backend resource. |\n| `cache` | disabled | No | Defines a cache service which stores the retrieved data from a backend resource but only when the ttl (within an ESI tag) has been set. Can only occur multiple times! |\n| `page_id_source` | `host`, `path` | No | Special directive on how to identify a request to the same page. The following settings can be used to calculate the hash value. Available settings: `remoteaddr`, `realip`, `scheme`, `host`, `path`, `rawpath`, `rawquery` and `url`. Special feature to access cookies and headers: Prefix with `cookie-` or `header-` to access the appropriate value. Attention: The more granular you define the higher possibility occurs that your RAM will be filled up (will be fixed ...). |\n| `allowed_methods` | `GET` | No | Any method listed here triggers the ESI middleware |\n| `cmd_header_name` | Disabled | No | Specify here a header name to enable certain commands for e.g. purging the internal ESI tag cache, setting log-level |\n| `log_file` | disabled | No | Put in here either a file name or the wordings `stderr` or `stdout` to write to those file descriptors. |\n| `log_level` | disabled | No | Available key words `debug` the most verbose and `info`, less verbose. |\n| `log_format` | n/a | No | Not yet supported. Ideas? |\n| `resources` | n/a | No | Additional configuration file in XML or JSON to refer to more backend resource services. |\n\n`cmd_header_name` current supported values are:\n\n- `purge` use the value `purge` with your defined `cmd_header_name` to purge the\nESI tag cache. `X-Esi-Cmd: purge`\n- `log-debug` enables debug logging. Costs heavily performance.\n- `log-info` enables info logging. Logs some errors and other note worthy informations.\n- `log-none` disables logging.\n\n`resources` defines the path to a configuration file for more backend resource\nservices. You need this file once CaddyESI has been enabled to work with other\nplugins as the default HTTP implementation. An example on how the XML or JSON\nmust be coded:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?\u003e\n\u003citems\u003e\n    \u003citem\u003e\n        \u003calias\u003eredis01\u003c/alias\u003e\n        \u003curl\u003e\u003c![CDATA[redis://127.0.0.1:6379/?db=0\u0026max_active=10\u0026max_idle=4]]\u003e\u003c/url\u003e\n        \u003c!--\u003cquery\u003eUnused and hence optional\u003c/query\u003e--\u003e\n    \u003c/item\u003e\n    \u003citem\u003e\n        \u003calias\u003egrpc01\u003c/alias\u003e\n        \u003curl\u003e\u003c![CDATA[grpc://127.0.0.1:53044/?timeout=60s\u0026tls=1\u0026ca_file=../path/to/root.pem\u0026server_host_override=my.domain.kom]]\u003e\u003c/url\u003e\n        \u003c!--\u003cquery\u003eUnused and hence optional\u003c/query\u003e--\u003e\n    \u003c/item\u003e\n    \u003citem\u003e\n        \u003calias\u003emysql01\u003c/alias\u003e\n        \u003curl\u003e\u003c![CDATA[mysql://user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8\u0026tls=skip-verify]]\u003e\u003c/url\u003e\n        \u003cquery\u003e\u003c![CDATA[SELECT `value` FROM tableX WHERE key='?']]\u003e\u003c/query\u003e \u003c!--Creates a long-lived prepared statement--\u003e\n    \u003c/item\u003e\n    \u003citem\u003e\n        \u003calias\u003emysql02\u003c/alias\u003e\n        \u003curl\u003emysql01\u003c/url\u003e\u003c!--Uses the connection of mysql01--\u003e\n        \u003cquery\u003e\u003c![CDATA[SELECT `value` FROM tableY WHERE another_key=?]]\u003e\u003c/query\u003e \u003c!--Creates a long-lived prepared statement--\u003e\n    \u003c/item\u003e\n\u003c/items\u003e\n```\n\n```json\n[\n  {\n    \"alias\": \"redis01\",\n    \"url\": \"redis://127.0.0.1:6379/?db=0\u0026max_active=10\u0026max_idle=4\"\n  },\n  {\n    \"alias\": \"grpc01\",\n    \"url\": \"grpc://127.0.0.1:53044/?timeout=60s\u0026tls=1\u0026ca_file=../path/to/root.pem\u0026server_host_override=my.domain.kom\"\n  },\n  {\n    \"alias\": \"mysql01\",\n    \"url\": \"mysql://user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8\u0026tls=skip-verify\",\n    \"query\": \"SELECT `value` FROM tableX WHERE key='?'\"\n  },\n  {\n    \"alias\": \"mysql02\",\n    \"url\": \"mysql01\",\n    \"query\": \"SELECT `value` FROM tableY WHERE another_key=?\"\n  }\n]\n```\n\nPlease be aware that this file must be stored securely on the hard drive and\nthat the owner of the Caddy process can read it. Other resource credential\nloading options might be added in the future.\n\nThe resource configuration file is only needed when other services besides HTTP\nare enabled.\n\nThe further usage of configuration gets explained in the ESI tag documentation.\n\n## Supported ESI Tags and their attributes\n\nImplemented:\n\n- [x] Caddy configuration parsing\n- [x] ESI tag parsing\n- [x] ESI tag replacement\n- [x] Background Fetcher workers\n- [x] Basic ESI Tag\n- [x] With timeout\n- [ ] With ttl\n- [x] Load local file after timeout for error handling\n- [ ] Flip src to AJAX call or HTTP2 push after timeout\n- [x] Forward all headers\n- [x] Forward some headers\n- [x] Forward POST,PATCH, PUT data\n- [ ] Return all headers\n- [ ] Return some headers\n- [x] Forward QUERY STRING and/or POST form data\n- [x] Multiple sources\n- [ ] Multiple sources with `race=\"true\"`\n- [x] Dynamic sources/keys (string replacement)\n- [ ] Conditional tag loading\n- [x] Redis access\n- [x] Memcache access\n- [ ] MySQL access\n- [ ] PGSQL access\n- [ ] fCGI access\n- [x] gRPC access\n- [x] Shell scripts/programs access (stderr|out|in) communication\n- [x] Query HTTP/S backend servers\n- [x] Handle compressed content from backends (Go http.Client)\n- [x] Coalesce multiple requests into one backend request\n\nOnly HTTP backend resources are enabled by default.\n\n### TL;DR ESI tag options\n\nQuick overview which options are available for two different kinds of ESI tags.\n\n1. Querying an HTTP backend (default enabled)\n\n```\n\u003cesi:include src=\"https://micro1.service/esi/foo\" src=\"https://microN.service/esi/foo\" \n    timeout=\"time.Duration\" ttl=\"time.Duration\" \n    onerror=\"text or path to file\" maxbodysize=\"bytes\"\n    forwardheaders=\"all or specific comma separated list of header names\"\n    returnheaders=\"all or specific comma separated list of header names\"\n    coalesce=\"true|false\" printdebug=\"true|false\"\n/\u003e\n```\n\n2. Querying a NOSQL database or gRPC service (not enabled)\n\n```\n\u003cesi:include src=\"alias_name1\" src=\"alias_nameN\" key=\"key name\" \n    onerror=\"text or path to file\" timeout=\"time.Duration\" coalesce=\"true|false\" printdebug=\"true|false\"/\u003e\n```\n\n`key` or `src` can contain variables which gets replaced to their corresponding\nvalues. See section \"Dynamic sources and keys\".\n\n### Basic tag\n\nThe basic tag waits on the `src` until `esi.timeout` cancels the loading. If src\ncontains an invalid URL or has not been specified at all, nothing happens.\n\nAn unreachable `src` gets marked as \"failed\" in the internal cache by a circuit\nbreaker with an exponential back-off strategy: 2ms, 4ms, 8ms, 16ms, 32ms ... or\nas defined in the `esi.timeout` or tag based `timeout` attribute.\n\nESI tags are getting internally cached after they have been parsed. Changes to\nESI tags during development must trigger a cache clearance via restarting or\nsending the correct `cmd_header_name` header key.\n\nA page ID defines the internal cache key for a set of ESI tags listed in an HTML\npage. For each incoming request the ESI processor knows beforehand which ESI\ntags to load and to process instead of parsing the HTML page sequentially. All\nESI `src` will be loaded parallel before the page output starts. Once the\ncontent has been received the Content-Length header gets calculated and the\noutput starts. \nTODO: Chunked transfer implementation with an immediately starting output.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" /\u003e\n```\n\n### With timeout (optional)\n\nThe basic tag with the attribute `timeout` waits for the src until the timeout\noccurs. After the timeout, the ESI tag gets not rendered and hence displays\nnothing. The attribute `timeout` overwrites the default `esi.timeout`.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" timeout=\"time.Duration\" /\u003e\n```\n\n100% Support with http/s requests to backend services.\n\n### With ttl (optional) (TODO)\n\nThe basic tag with the attribute `ttl` stores the returned data from the `src`\nin the specified `esi.backend`. The attribute `ttl` overwrites the default\n`esi.ttl`. If `esi.backend` has not been set or `ttl` set to empty, caching is\ndisabled.\n\n`esi.backend` uses the `src` as a cache key.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" ttl=\"time.Duration\" /\u003e\n```\n \n### Load local file after timeout (optional)\n\nThe basic tag with the attribute `timeout` waits for the src until the timeout\noccurs. After the timeout, the ESI processor loads the local file or text from\nthe attribute `onerror` and renders it into the page. If the file does not\nexists an ugly error gets shown.\n\nSupported file extensions: `\"html\", \"htm\", \"xml\", \"txt\", \"json\"`\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" timeout=\"time.Duration\" onerror=\"path/to/mylocalFile.html\"/\u003e\n\n\u003cesi:include src=\"https://micro.service/esi/foo\" timeout=\"time.Duration\" onerror=\"Cannot load weather service\"/\u003e\n```\n\n### Max body size to limit the size of the body returned from a backend (optional)\n\nThe basic tag with the attribute `maxbodysize=\"size\"` takes care that the\nreturned body size has been limited to the provided value. Default body size is\n5 MB. Other attributes can be additionally defined.\nAvailable size identifiers: [https://github.com/dustin/go-humanize/blob/master/bytes.go#L34](https://github.com/dustin/go-humanize/blob/master/bytes.go#L34)\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" maxbodysize=\"3MB\"/\u003e\n```\n\n### Flip src to AJAX call after timeout (optional) (TODO)\n\nThe basic tag with the attribute `timeout` waits for the src until the timeout\noccurs. After the timeout, the ESI processor converts the URI in the `src`\nattribute to an AJAX call in the frontend. The attribute `onerror=\"ajax\"` must\nexists or feature is disabled. TODO: JS code of the template ...\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" timeout=\"time.Duration\" onerror=\"ajax\"/\u003e\n```\n\n### Forward POST, PATCH or PUT data (optional)\n\nThe basic tag with the attribute `forwardpostdata` forwards all incoming request\nPOST, PATCH, PUT data to the `src`. Other attributes can be additionally\ndefined. Default value `false` which does not forward anything. POST data gets\nonly forwarded to those backend resources which can handle the data.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" forwardpostdata=\"true\"/\u003e\n```\n\n### Forward all headers (optional)\n\nThe basic tag with the attribute `forwardheaders` forwards all incoming request\nheaders to the `src`. Other attributes can be additionally defined. POST data\ngets only forwarded to those backend resources which can handle the data.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" forwardheaders=\"all\"/\u003e\n```\n\n### Forward some headers (optional)\n\nThe basic tag with the attribute `forwardheaders` forwards only the specified\nheaders of the incoming request to the `src`. Other attributes can be\nadditionally defined. POST data gets only forwarded to those backend resources\nwhich can handle the data.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" forwardheaders=\"Cookie,Accept-Language,Authorization\"/\u003e\n```\n\n### Return all headers (optional) (TODO)\n\nThe basic tag with the attribute `returnheaders` returns all `src` headers to\nthe final response. Other attributes can be additionally defined. If duplicate\nheaders from multiple sources occurs, they are getting appended to the response.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" returnheaders=\"all\"/\u003e\n```\n\n### Return some headers (optional) (TODO)\n\nThe basic tag with the attribute `returnheaders` returns the listed headers of\nthe `src` to the final response. Other attributes can be additionally defined. If\nduplicate headers from multiple sources occurs, they are getting appended to the\nresponse.\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" returnheaders=\"Set-Cookie\"/\u003e\n```\n\n### Coalesce multiple requests into one backend request (optional)\n\nThe basic tag with the attribute `coalesce=\"boolean\"` takes care that for\nmultiple incoming requests only one backend request gets fired. Other parallel\nincoming requests waits until the backend returns from the initializing request.\nAny returned data from a backend resource gets shared with an unknown number of\nexternal requests. This feature limits the pressure onto a backend resource.\nOther attributes can be additionally defined. Default value `false`, hence\ndisabled.\n`coalesce=\"false|true|1|0\"`\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" coalesce=\"true\"/\u003e\n```\n\n### Printdebug (optional)\n\nThe basic tag with the attribute `printdebug=\"boolean\"` allows to print\ndebugging information as an HTML comment. Debugging contains the time taken to\ncomplete the backend request, any possible error and the raw tag itself. Be\naware that if you store sensitive information in the raw tag they will leak\ntowards the evil internet. Other attributes can be additionally defined. Default\nvalue `false`, hence disabled.\n`printdebug=\"false|true|1|0\"`\n\n```\n\u003cesi:include src=\"https://micro.service/esi/foo\" printdebug=\"true\"/\u003e\n```\n\n### Multiple sources\n\nThe basic ESI tag can contain multiple sources. The ESI processor tries to load\n`src` attributes in its specified order. The next `src` gets called after the\n`esi.timeout` or `timeout` occurs. Other attributes can be additionally defined.\nAdd the attribute `race=\"true\"` (TODO) to fire all requests at once and the one which\nis the fastest gets served and the others dropped.\n\n```\n\u003cesi:include \n    src=\"https://micro1.service/esi/foo\" \n    src=\"http://micro2.service/esi/foo\"\n    src=\"https://micro3.service/esi/foo\" \n    timeout=\"time.Duration\" \n    race=\"boolean\" /\u003e\n```\n\n### Dynamic sources and keys (string replacement)\n\nThe basic ESI tag can extend all `src` URLs and `key` attributes with additional\nparameters from the `http.Request` object. A replacement string must be one of\nthe listed below and must consists of the pattern: `{[^\\}]+}`. Replacement\nstrings can occur anywhere and n-times in the `src` or `key` attribute.\n\n```\n\u003cesi:include src=\"http://micro.service/search?query={Fsearch_term}\"/\u003e\n\u003cesi:include src=\"https://micro.service/{dir}/{file}/?id={HMy-Header-Key}\"/\u003e\n```\n\nThe following string replacements are possible:\n\n- {method}\n- {scheme}\n- {hostname}\n- {host} (incl. port)\n- {hostonly} (excl. port)\n- {path}         (header Caddy-Rewrite-Original-URI supported)\n- {path_escaped} (header Caddy-Rewrite-Original-URI supported)\n- {rewrite_path}\n- {rewrite_path_escaped}\n- {query}\n- {query_escaped}\n- {fragment}\n- {proto}\n- {remote} IP address, might not be the real IP address\n- {real_remote} real IP address\n- {port}\n- {uri} the RequestURI\n- {uri_escaped} the RequestURI\n- {when}\n- {when_iso}\n- {file}\n- {dir}\n\nTo access any value in the header, cookie, GET form or POST form you can write a\nspecial crafted replacement string.\n\n- {HMy-Header-Key-Name} must start with `H` followed by the header key name\n(case in-sensitive), in this case: `My-Header-Key-Name`.\n- {CMy-Cookie-Name} must start with `C` followed by the cookie name (case\nsensitive), in this case: `My-Cookie-Name`.\n- {FMy-Input-Name} must start with `F` followed by the name of the field (case\nsensitive), in this case: `My-Input-Name`.\n\n### Conditional tag loading (TODO)\n\nThe basic ESI tag can contain the attribute `condition`. A `condition` must\nevaluate an expression to `true` to trigger the loading of the `src`.\n\n```\n\u003cesi:include src=\"http://micro.service/search?query={Fquery}\"\n    condition=\"{hostname} eq 'customer.micro.service'\"/\u003e\n```\n\n### Access via src aliases\n\nThe ESI processor can access NoSQL, gRPC and SQL resources which are specified\nin the Caddy resources configuration file. The `src` attribute must contain the\nvalid alias name as defined in resources file. The ESI tag must contain a `key`\nattribute which accesses the value in the NoSQL server or forwards that value to\ngRPC or uses it in the SELECT query for a database. The returned value will be\nrendered unmodified into the HTML page output. You are responsible for secure\nescaping of your data. If multiple `src` tags are defined the next `src` gets\nused once the key cannot be found in the previous source or the `timeout`\napplies. Return and forward headers might not be supported.\n\n```\n\u003cesi:include src=\"redisAWS1\" src=\"redisLocal1\" key=\"my_redis_key_x\" timeout=\"time.Duration\" /\u003e\n\u003cesi:include src=\"redisAWS1\" key=\"my_redis_key_x\" onerror=\"myLocalFile.html\" timeout=\"time.Duration\" /\u003e\n\u003cesi:include src=\"redis1\" key=\"prefix_{host}_{HX-Whatever}\" timeout=\"time.Duration\" /\u003e\n```\n\n### General ESI tag attribute handling\n\nUnrecognized attributes within an `\u003cesi:include` will trigger a parse error. Protects you from fat fingers ;-)\n\n*ProTip:* To disable an attribute instead of removing it from the tag you can prepend it with an `x`.\nSo `src=\"...\"` will become `xsrc=\"...\"`.\n\n### Registered schemes or aliases in the src attribute\n\nThe `src` attribute can contain or refer to the following aliases (defined in\nthe resource configuration file) to fetch content from a resource backend:\n\n- http://\n- https://\n- sh://\n- Name of the aliases as defined in the resources file\n\nTo access the next resources you must specify them as an alias in the resources\n`xml|json` file. Because those connection lives the whole Caddy process and\nmight never get closed.\n\n- redis://\n- memcache://\n- sql:// a SQL query (TODO)\n- grpc:// a remote procedure call with gRPC\n\n#### HTTP / HTTPS\n\n`http|s` allows the usual HTTP requests to a resource.\n\nAlways enabled.\n\n#### sh shell\n\n`sh` starts a shell program or any other executable script. The incoming HTTP\nrequest plus the current arguments gets transformed into a JSON string and will\nbe passed as first argument to the program via stdin. If the program writes to\nstderr CaddyESI recognizes that and triggers it as an usual error. Too many\nerrors and the circuit breaker opens. To output towards the HTTP response gets written\nto stdout. The src attribute must look like:\n\n```html\n\u003cesi:include src=\"sh:///path/to/myGoBinary\" /\u003e\n\u003cesi:include src=\"sh:///path/to/my/slow/php/script.php\" /\u003e\n\u003cesi:include src=\"sh:///path/to/my/slow/php/script.php --arg1 --arg2=x --argN=y\" /\u003e\n\n\u003cesi:include src=\"sh://php /path/to/my/slow/php/script.php\" /\u003e\n```\n\n*ProTip:* Provide always the full path to the binary or script because the\nlookup time in the operation systems environment PATH variable will take long.\nIn general shell execution is pretty slow no matter which kind of\nprogram/script you call.\n\nDisabled by default and must be enabled with a new compiled Caddy binary and the\nbuild tag `esishell`.\n\n#### SQL queries TODO\n\n`sql` Uses a prepared statement once the ESI tag has been parsed.\n\n```html\n\u003cesi:include src=\"alias_name\" key=\"{FMyFormInputName}\" /\u003e\n```\n\n`key` will be used as parameter in the WHERE query part.\n\nDisabled by default and must be enabled with a new compiled Caddy binary and the\nbuild tag `esisql`.\n\n#### gRPC Remote Procedure Calls\n\n`grpc` queries another gRPC endpoint. A struct of arguments gets encoded and\npassed over the wire.\n\n```html\n\u003cesi:include src=\"alias_name\" key=\"cart1\" /\u003e\n```\n\nYou are responsible for building the gRPC server. The `.proto` file and the\ncorresponding Go file have been placed in package `backend/esigrpc`. Your gRPC\nserver can run in any programming language you like and is supported by gRPC.\n[https://www.grpc.io](https://www.grpc.io)\n\nDisabled by default and must be enabled with a new compiled Caddy binary and the\nbuild tag `esigrpc`.\n\n## Unsupported ESI Tags\n\nAll other tags, as defined in\n[https://www.w3.org/TR/esi-lang](https://www.w3.org/TR/esi-lang), won't be\nsupported. You should switch to a server side scripting language ;-).\n\n# Building\n\nThe following command enables HTTP/S/2 backends:\n\n```bash\n$ go get -u github.com/caddyserver/caddy/...\n# maybe checkout different version of caddy. Tested with 0.9.5\n$ go get -u github.com/SchumacherDM/caddyesi/...\n```\n\nIn file `$GOPATH/src/github.com/caddyserver/caddy/caddy/caddymain/run.go` add the line\n`_ \"github.com/corestoreio/caddy-esi\"` after the text `// This is where other plugins get plugged in (imported)`.\n\nIn file `$GOPATH/src/github.com/caddyserver/caddy/caddyhttp/httpserver/plugin.go` find\nthe variable `directives` and add the entry `\"esi\",` between `hugo` and\n`mailout`. At the moment I'm not quite sure if that is the correct place. If any\nother middleware fails, you should change the position of the `esi` entry to\nsomewhere else. Please report back here by opening an issue.\n\nThen you are ready to compile Caddy with ESI support:\n\n```\n$ GOOS=linux GOARCH=amd64 go build -o caddyesi $GOPATH/src/github.com/caddyserver/caddy/caddy/main.go\n```\n\nChange `GOOS` and `GOARCH` to whatever architecture and operating system you are targeting.\n\n# Contribute\n\nSend me a pull request or open an issue if you encounter a bug or something can\nbe improved!\n\nMulti-time pull request senders gets collaborator access.\n\n# Attribution\n\n### github.com/vdobler/ht\n\nCopyright (c) 2014, Volker Dobler\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this\n  list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of ht nor the names of its\n  contributors may be used to endorse or promote products derived from\n  this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n### github.com/dustin/go-humanize\n\n```text\nCopyright (c) 2005-2008  Dustin Sallings \u003cdustin@spy.net\u003e\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n\u003chttp://www.opensource.org/licenses/mit-license.php\u003e\n```\n\n### github.com/uber-go/zap\n\n```text\nCopyright (c) 2016 Uber Technologies, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n```\n\n### github.com/bradfitz/gomemcache\n\n```text\nCopyright 2011 Google Inc.\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n```\n\n### github.com/gomodule/redigo\n\n```text\nCopyright 2012 Gary Burd\n\nLicensed under the Apache License, Version 2.0 (the \"License\"): you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n```\n\n### google.golang.org/grpc\n\n```text\nCopyright 2016, Google Inc.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n    * Redistributions of source code must retain the above copyright\nnotice, this list of conditions and the following disclaimer.\n    * Redistributions in binary form must reproduce the above\ncopyright notice, this list of conditions and the following disclaimer\nin the documentation and/or other materials provided with the\ndistribution.\n    * Neither the name of Google Inc. nor the names of its\ncontributors may be used to endorse or promote products derived from\nthis software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n```\n\n# License\n\n[Cyrill Schumacher](https://github.com/SchumacherFM) - [My pgp public key](https://www.schumacher.fm/cyrill.asc)\n\nCopyright 2016 Cyrill Schumacher All Rights Reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\nthis file except in compliance with the License. You may obtain a copy of the\nLicense at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software distributed\nunder the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\nCONDITIONS OF ANY KIND, either express or implied. See the License for the\nspecific language governing permissions and limitations under the License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorestoreio%2Fcaddy-esi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcorestoreio%2Fcaddy-esi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcorestoreio%2Fcaddy-esi/lists"}