summaryrefslogtreecommitdiff
path: root/main/SAPI.c
blob: 1df5fe4fea85e04411cd9ee0db503ae5fb6caaee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
   +----------------------------------------------------------------------+
   | Server API Abstraction Layer                                         |
   +----------------------------------------------------------------------+
   | Copyright (c) 1999 SAPI Development Team                             |
   +----------------------------------------------------------------------+
   | This source file is subject to the GNU public license, that is       |
   | bundled with this package in the file LICENSE.                       |
   +----------------------------------------------------------------------+
   | Design:  Shane Caraveo <shane@caraveo.com>                           |
   | Authors: Andi Gutmans <andi@zend.com>                                |
   |          Zeev Suraski <zeev@zend.com>                                |
   +----------------------------------------------------------------------+
*/


#include "SAPI.h"
#ifdef ZTS
#include "TSRM.h"
#endif

#if WIN32||WINNT
#define STRCASECMP stricmp
#else
#define STRCASECMP strcasecmp
#endif


SAPI_API void (*sapi_error)(int error_type, const char *message, ...);


#ifdef ZTS
SAPI_API int sapi_globals_id;
#else
sapi_globals_struct sapi_globals;
#endif


/* True globals (no need for thread safety) */
sapi_module_struct sapi_module;
SAPI_API void (*sapi_error)(int error_type, const char *message, ...);


SAPI_API void sapi_startup(sapi_module_struct *sf)
{
	sapi_module = *sf;
#ifdef ZTS
	sapi_globals_id = ts_allocate_id(sizeof(sapi_globals_struct), NULL, NULL);
#endif
}


static void sapi_free_header(sapi_header_struct *sapi_header)
{
	efree(sapi_header->header);
}


SAPI_API void sapi_activate(SLS_D)
{
	zend_llist_init(&SG(sapi_headers).headers, sizeof(sapi_header_struct), (void (*)(void *)) sapi_free_header, 0);
	SG(sapi_headers).content_type.header = NULL;
	SG(sapi_headers).http_response_code = 200;
	SG(headers_sent) = 0;
}


SAPI_API void sapi_deactivate(SLS_D)
{
	zend_llist_destroy(&SG(sapi_headers).headers);
	if (SG(sapi_headers).content_type.header) {
		efree(SG(sapi_headers).content_type.header);
	}
}


/* This function expects a *duplicated* string, that was previously emalloc()'d.
 * Pointers sent to this functions will be automatically freed by the framework.
 */
SAPI_API int sapi_add_header(char *header_line, uint header_line_len)
{
	int retval;
	sapi_header_struct sapi_header;
	SLS_FETCH();

	if (SG(headers_sent)) {
		sapi_module.sapi_error(E_WARNING, "Cannot add header information - headers already sent");
		efree(header_line);
		return FAILURE;
	}

	sapi_header.header = header_line;
	sapi_header.header_len = header_line_len;

	if (sapi_module.header_handler) {
		retval = sapi_module.header_handler(&sapi_header, &SG(sapi_headers));
	} else {
		retval = SAPI_HEADER_ADD;
	}

	if (retval & SAPI_HEADER_DELETE_ALL) {
		zend_llist_clean(&SG(sapi_headers).headers);
	}
	if (retval & SAPI_HEADER_ADD) {
		char *colon_offset = strchr(header_line, ':');

		if (colon_offset) {
			*colon_offset = 0;
			if (!STRCASECMP(header_line, "Content-Type")) {
				if (SG(sapi_headers).content_type.header) {
					efree(SG(sapi_headers).content_type.header);
				}
				*colon_offset = ':';
				SG(sapi_headers).content_type.header = (char *) header_line;
				SG(sapi_headers).content_type.header_len = header_line_len;
				return SUCCESS;
			}
			*colon_offset = ':';
		}
		zend_llist_add_element(&SG(sapi_headers).headers, (void *) &sapi_header);
	}
	return SUCCESS;
}


SAPI_API int sapi_send_headers()
{
	int retval;
	sapi_header_struct default_header = { SAPI_DEFAULT_CONTENT_TYPE, sizeof(SAPI_DEFAULT_CONTENT_TYPE)-1 };
	SLS_FETCH();

	if (SG(headers_sent)) {
		return SUCCESS;
	}

	if (sapi_module.send_headers) {
		retval = sapi_module.send_headers(&SG(sapi_headers) SLS_CC);
	} else {
		retval = SAPI_HEADER_DO_SEND;
	}

	switch (retval) {
		case SAPI_HEADER_SENT_SUCCESSFULLY:
			SG(headers_sent) = 1;
			return SUCCESS;
			break;
		case SAPI_HEADER_DO_SEND:
			if (SG(sapi_headers).content_type.header) {
				sapi_module.send_header(&SG(sapi_headers).content_type, SG(server_context));
			} else {
				sapi_module.send_header(&default_header, SG(server_context));
			}
			zend_llist_apply_with_argument(&SG(sapi_headers).headers, (void (*)(void *, void *)) sapi_module.send_header, SG(server_context));
			sapi_module.send_header(NULL, SG(server_context));
			SG(headers_sent) = 1;
			return SUCCESS;
			break;
		case SAPI_HEADER_SEND_FAILED:
			return FAILURE;
			break;
	}
	return FAILURE;
}