static-httpd /sources/http_util.cpp

Language C++ Lines 378
MD5 Hash 50ebac25cbcbe2c338f1e1fb9eba3cb9
Repository https://github.com/andreisavu/static-httpd.git View Raw File View Project SPDX
  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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
// HTTP Server utility classes
/*

Functii utile pentru server

(c) GarajCode 2005-2006 - programmed by Savu Andrei
Date : 27 februarie 2006
Last date : 27 februarie 2006

*/

#include "http_util.h"

// Garaj Network Framework
namespace GN
{

// Definire clasa pentru preprocesare cerere HTTP

/// Procesare cerere HTTP
/**
	Aceasta functie extrage din cererea HTTP metoda de cerere,
	url-ul, versiunea implementarii http si toti parametrii
	care urmeaza. r - cererea Http  l-lungimea ei
  */
void HttpRequest::parse( char * r, int l )
{
	char *p = r, *v;
	int i=0;
	
	// extrage metoda folosita - mergi pana la primul spatiu.
	while( r[i]!=' ' && i<l ) i++;
	r[i] = 0;
	m_method = p;
	i++;

	// extrage url - care nu contine spatii 
	while( r[i]==' ' && i<l ) i++;
	p = &r[i];
	while( r[i]!=' ' && i<l ) i++;
	r[i]=0;
	m_url = p;
	i++;

	// extrage versiune http - pana la primul \n
	while( r[i]==' ' && i<l ) i++;
	p = &r[i];
	while( r[i]!='\n' && i<l ) i++;
	r[i]=0;
	m_http_version = p;
	i++;

	// extrage restul parametrilor care
	// sunt trimisi sub forma <nume>: <valoare>\n
	do
	{
		if( r[i]=='\n' || r[i+1]=='\n' ) break;

		// extrage numele
		p = &r[i];
		while( r[i]!=':' && r[i]!='\n' && r[i]!=' ' && i<l ) i++;
		r[i]=0; i++;
		while( r[i]==' ' && i<l ) i++;
	
		// extrage valoarea
		v = &r[i];
		while( r[i]!='\n' && i<l ) i++;
		r[i-1] = 0;

		// creaza o variabila cu numele si valoarea gasita
		m_ini.set( p, v );
		i++;
		
	}while( 1 );
}

/// Converteste un numar din hexa in dec
inline int hex1_to_dec( char a )
{
	// daca e cifra
	if( a>='0' && a<='9' ) return a-'0';

	// daca e litera mica
	if( a>='a' && a<='f') return a-'a';

	// daca e litera mare 
	if( a>='A' && a<='F' ) return a-'A';

	// eroare - cifra necunoscuta
	return -1;
}


/// Converteste un numar hexa
/**
	Functie folosita pentru decodarea 
	url. Converteste un numar hexa de doua
	cifre intr-un numar intreg
  */
inline int hex2_to_dec( char a, char b )
{
	int c1 = hex1_to_dec(a), c2 = hex1_to_dec(b);
	if( c1==-1 || c2==-1 ) 
	{
		// eroare - a aparut un caracter necunoscut
		return -1;   
	}
	return c1*16+c2;
}


/// Decodare URL
/**
	Decodare URL - inlocuieste grupurile de trei
	litere care incep cu % cu caracterul ASCII 
	corespunzator.
  */
int HttpUrl::decode( char * url )
{
	int l = strlen(url), i=0, j=0, aux;
		
	while( i<l )
	{
		if( url[i]=='%' )
		{
			// urmatoarele doua caractere sunt un numar
			aux = hex2_to_dec( url[i+1], url[i+2] );
			if( aux == -1 ) return 0;	

			// pune caracterul corespunzator
			url[j] = (char)aux;
			i+=3;
			j++;
		}
		else 
		{
			// copiaza caracterul pur si simplu
			url[j] = url[i];
			if( url[j]=='/' ) url[j]='\\';
			i++;
			j++;
		}
	}

	url[j] = 0;

	return 1;
}	

/// Procesare url
/**
	Imparte url-ul in componente logice. 
	Nume fisier + eventuale variabile trimise prin GET
*/
int HttpUrl::parse( const char * http_url, const char * base_folder )
{
	// copiaza sirul de caractere din url
	char *url, *ext;
	if( !(url = new char[ strlen(http_url)+2 ]) ) return 0;
	strcpy( url, http_url );

	// decodeaza url-ul - caracterele care incep cu %
	if( !decode( url ) ) return 0;

	// proceseaza url
	char *p = url;
	int i=0, l=strlen(url);

	// extrage numele fisierului, pana la primul ? sau #
	// si extensia pentru a putea stabilii content-type
	ext = NULL;
	while( url[i]!='?' && url[i]!='#' && i<l ) 
	{
		if( url[i] == '.' ) ext = &url[i+1];
		i++;
	}
	url[i] = 0;

	m_file = base_folder;
	m_file += p;
	if( ext ) m_ext = ext;

	// verifica daca avem sau nu nume de fisier
	if( p[strlen(p)-1] == '\\' ) 
	{
		m_file += "index.html";
		m_ext = "html";
	}
	i++;
	
	// extrage string-ul pentru query
	p = &url[i];
	while( url[i]!='#' && i<l ) i++;
	url[i] = 0;
	m_query = p;

	// proceseaza string si extrage valorile
	// valorile sunt separate prin = si &
	l = strlen(p);
	char *r = p;
	i = 0;

	char *nume, *valoare;
	bool has_value;
	while( i<l )
	{
		// extrage numele
		nume = &p[i];
		has_value = true;
		while( p[i]!='=' && p[i]!='&' && i<l ) i++;
		if( p[i] == '&' ) 
		{
			// avem doar numele
			has_value = false;
			valoare = NULL;
		}
		p[i] = 0;
		i++;
		
		// extrage valoarea
		if( has_value )
		{
			valoare = &p[i];
			while( p[i]!='&' && i<l ) i++;
			p[i] = 0; 
			i++;
		}

		// adauga o variabila cu acest nume
		m_ini.set( nume, valoare );

	}

	// elibereaza memoria folosita
	delete[] url;

	return 1;
}

// trimite new line - \n
inline nwl( GN::CSocket& s )
{
	try
	{
		char n = '\n';
		s << n;
	}
	catch(...)
	{
		throw;
	}
}

/// Trimite header de raspuns http
/**
	Trimite header de raspuns pentru cererea 
	http. Header-ul poate contine orice.
  */
void HttpResponse::send( GN::CSocket& s )
{
	// trimite prima linie si apoi
	// fiecare variabila sub forma <nume>: <valoare>\n
	// header-ul se incheie cu un \n dublu

	if( m_sent ) return;
	
	try
	{
		s.send( m_txt.c_str(), m_txt.length() ); nwl(s);

		// MessageBox( NULL, m_txt.c_str(), "dfg", MB_OK );

		for( GSTD::CIni::iterator it=m_ini.begin(); it!=m_ini.end(); it++ )
		{
			//	MessageBox( NULL, (*it).second,(*it).first.c_str() , MB_OK );
			if( (*it).second.get_size() )
			{
				s.send( (*it).first.c_str(), (*it).first.length() );
				s.send( ": ", 2 );
				s.send( (*it).second, (*it).second.get_size() );
				nwl(s);
			}
		}

		nwl(s);

		m_sent = true;
	}
	catch(...)
	{
		throw;
	}
}

/// Set HTTP Response header
void HttpResponse::set_status( int code )
{
	switch( code )
	{
	case HTTP_OK:
		set_status( "HTTP/1.0 200 OK" );
		break;

	case HTTP_CREATED:
		set_status( "HTTP/1.0 201 Created" );
		break;

	case HTTP_ACCEPTED:
		set_status( "HTTP/1.0 202 Accepted" );
		break;

	case HTTP_NO_CONTENT:
		set_status( "HTTP/1.0 204 No Content" );
		break;
	

	case HTTP_REDIRECT:
		set_status( "HTTP/1.0 300 Multiple choice" );
		break;

	case HTTP_MOVED_PERMANENTLY:
		set_status( "HTTP/1.0 301 Moved Permanently" );
		break;

	case HTTP_MOVED_TEMPORARILY:
		set_status( "HTTP/1.0 302 Moved Temporarily" );
		break;

	case HTTP_NOT_MODIFIED:
		set_status( "HTTP/1.0 304 Not Modified" );
		break;

	case HTTP_BAD_REQUEST:
		set_status( "HTTP/1.0 400 Bad request" );
		break;

	case HTTP_UNAUTHORIZED:
		set_status( "HTTP/1.0 401 Unauthorized" );
		break;

	case HTTP_FORBIDDEN:
		set_status( "HTTP/1.0 403 Forbidden" );
		break;

	case HTTP_NOT_FOUND:
		set_status( "HTTP/1.0 404 Not Found" );
		break;

	case HTTP_SERVER_ERROR:
		set_status( "HTTP/1.0 500 Internal Server Error" );
		break;

	case HTTP_NOT_IMPLEMENTED:
		set_status( "HTTP/1.0 501 Not Implemented" );
		break;

	case HTTP_BAD_GATEWAY:
		set_status( "HTTP/1.0 502 Bad Gateway" );
		break;

	case HTTP_SERVICE_UNAVAIBLE:
		set_status( "HTTP/1.0 503 Service Unavaible" );
		break;
	}
}

/// Seteaza raspuns HTTP pentru redirectare
void HttpResponse::redirect( char * dest )
{
	set_status( HTTP_REDIRECT );
	set( "Location", dest );

}


};	// GN
Back to Top