<commit_before># Coprocess (Python)

This feature makes it possible to write Tyk middleware using [Python](https://www.python.org/), the current binding supports Python 3.x.
The purpose of this README is to provide an overview of the architecture and a few implementation notes.

## Usage

You'll need to build Tyk with specific build tags, see build notes below.

Basically `go build -tags 'coprocess python'`.

### Setting up custom Python middleware

The custom middleware should be specified in your API definition file, under `custom_middleware` (see [coprocess_app_sample.json](coprocess_app_sample.json)):

```json
"custom_middleware": {
  "pre": [
      {
        "name": "MyPreMiddleware",
        "require_session": false
      }
    ],
  "post": [
    {
        "name": "MyPostMiddleware",
        "require_session": false
    }
  ],
  "driver": "python"
}
```

You can chain multiple hook functions when the hook type is Pre, Post or PostAuthCheck.

Tyk will load all the modules inside `middleware/python`.

The "name" field represents the name of a Python function, a sample Python middleware matching the sample definition above will look like (see [middleware/python](middleware/python)):

```python
from tyk.decorators import *

@Pre
def MyPreMiddleware(request, session, spec):
    print("my_middleware: MyPreMiddleware")
    return request, session

@Post
def MyPreMiddleware(request, session, spec):
    print("my_middleware: MyPreMiddleware")
    return request, session
```

### Authenticating an API with Python

This is a sample API definition that will let you authenticate your API using a custom Python middleware (see [coprocess_app_sample_protected.json](coprocess_app_sample_protected)):
```json
...
"use_keyless": false,
"enable_coprocess_auth": true,
"custom_middleware": {
  "auth_check": {
    "name": "MyAuthCheck"
  },
  "driver": "python"
},
...
```

The Python code for this middleware will look like this (see [my_auth_middleware.py](my_auth_middleware.py)):
```python
from tyk.decorators import *
from gateway import TykGateway as tyk

from tyk.session import AccessSpec, AccessDefinition, BasicAuthData, JWTData, Monitor

@CustomKeyCheck
def MyAuthCheck(request, session, metadata, spec):
    print("my_auth_middleware: CustomKeyCheck hook")

    print("my_auth_middleware - Request:", request)
    print("my_auth_middleware - Session:", session)
    print("my_auth_middleware - Spec:", spec)

    valid_token = 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
    request_token = request.get_header('Authorization')

    print("my_auth_middleware - Request Token:", request_token)

    if request_token == valid_token:
        session.rate = 1000.0
        session.per = 1.0

        metadata['token'] = 'my<PASSWORD>'
    else:
        # Invalid token!
        request.object.return_overrides.response_code = 401
        request.object.return_overrides.response_error = 'Not authorized (Python middleware)'

    return request, session, metadata
```

## Build requirements

* [Python 3.x](https://www.python.org/)
* [Go](https://golang.org)
* [Cython](http://cython.org/) (required if you need to modify and re-compile the gateway API binding)
* [protobuf](https://pypi.python.org/pypi/protobuf/3.0.0) (Python module): `pip install protobuf`

## Build steps
<commit_msg>Adding documentation for Python event handlers<commit_after># Coprocess (Python)

This feature makes it possible to write Tyk middleware using [Python](https://www.python.org/), the current binding supports Python 3.x.
The purpose of this README is to provide an overview of the architecture and a few implementation notes.

## Usage

You'll need to build Tyk with specific build tags, see build notes below.

Basically `go build -tags 'coprocess python'`.

### Setting up custom Python middleware

The custom middleware should be specified in your API definition file, under `custom_middleware` (see [coprocess_app_sample.json](coprocess_app_sample.json)):

```json
"custom_middleware": {
  "pre": [
      {
        "name": "MyPreMiddleware",
        "require_session": false
      }
    ],
  "post": [
    {
        "name": "MyPostMiddleware",
        "require_session": false
    }
  ],
  "driver": "python"
}
```

You can chain multiple hook functions when the hook type is Pre, Post or PostAuthCheck.

Tyk will load all the modules inside `middleware/python`.

The "name" field represents the name of a Python function, a sample Python middleware matching the sample definition above will look like (see [middleware/python](middleware/python)):

```python
from tyk.decorators import *

@Pre
def MyPreMiddleware(request, session, spec):
    print("my_middleware: MyPreMiddleware")
    return request, session

@Post
def MyPreMiddleware(request, session, spec):
    print("my_middleware: MyPreMiddleware")
    return request, session
```

### Authenticating an API with Python

This is a sample API definition that will let you authenticate your API using a custom Python middleware (see [coprocess_app_sample_protected.json](coprocess_app_sample_protected)):
```json
...
"use_keyless": false,
"enable_coprocess_auth": true,
"custom_middleware": {
  "auth_check": {
    "name": "MyAuthCheck"
  },
  "driver": "python"
},
...
```

The Python code for this middleware will look like this (see [my_auth_middleware.py](my_auth_middleware.py)):
```python
from tyk.decorators import *
from gateway import TykGateway as tyk

from tyk.session import AccessSpec, AccessDefinition, BasicAuthData, JWTData, Monitor

@CustomKeyCheck
def MyAuthCheck(request, session, metadata, spec):
    print("my_auth_middleware: CustomKeyCheck hook")

    print("my_auth_middleware - Request:", request)
    print("my_auth_middleware - Session:", session)
    print("my_auth_middleware - Spec:", spec)

    valid_token = 'aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d'
    request_token = request.get_header('Authorization')

    print("my_auth_middleware - Request Token:", request_token)

    if request_token == valid_token:
        session.rate = 1000.0
        session.per = 1.0

        metadata['token'] = 'mytoken'
    else:
        # Invalid token!
        request.object.return_overrides.response_code = 401
        request.object.return_overrides.response_error = 'Not authorized (Python middleware)'

    return request, session, metadata
```

### Writing events handlers with Python

It's also possible to write a Tyk event listener with Python. The first step is to set a custom event handler inside your API definition (see [coprocess_app_sample_protected](coprocess_app_sample_protected)):

```json
...
"event_handlers": {
  "events": {
    "AuthFailure": [
      {
        "handler_name": "cp_dynamic_handler",
        "handler_meta": {
          "name": "my_handler"
        }
      }
    ]
  }
},
...
```

In the above sample we're setting an event handler for `AuthFailure` events, an event that's triggered everytime a failed authentication occurs.

The `handler_name` must be `cp_dynamic_handler`.

The `name` field inside `handler_meta` refers to a Python function name that can be written inside `event_handlers` (see [event_handlers/my_handler.py](event_handlers/my_handler.py)):

```python
from tyk.decorators import Event

@Event
def my_handler(event, spec):
    print("-- my_handler:")
    print(" Event:", event)
    print(" Spec:", spec)
```

This function will be called when the specified event occurs, Tyk will pass a Python object like this:

```json
{  
   "TimeStamp": "2016-08-19 11:13:31.537047694 -0400 PYT",
   "EventMetaData":{  
      "Path":"/coprocess-auth-tyk-api-test/",
      "Origin":"127.0.0.1",
      "Message":"Auth Failure",
      "OriginatingRequest":"<KEY>
      "Key":""
   },
   "EventType": "AuthFailure"
}
```

The above handler can be tested by sending a HTTP request to the protected Coprocess API, with an invalid authorization header:

```
curl http://127.0.0.1:8080/coprocess-auth-tyk-api-test/ -H 'Authorization: invalidtoken'
```

## Build requirements

* [Python 3.x](https://www.python.org/)
* [Go](https://golang.org)
* [Cython](http://cython.org/) (required if you need to modify and re-compile the gateway API binding)
* [protobuf](https://pypi.python.org/pypi/protobuf/3.0.0) (Python module): `pip install protobuf`

## Build steps

{'fraction_non_alphanumeric': 0.11313692344844241, 'fraction_numerical': 0.012678097078000484, 'mean_word_length': 4.176875, 'pattern_counts': {'":': 42, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 8, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4120152', 'n_tokens_mistral': 2590, 'n_tokens_neox': 2478, 'n_words': 775}