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 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341
|
eCgiLib 0.6
Documentation & Manual
Index
1 Introduction 4
1.1 What is eCgiLib ? 4
1.2 History 4
1.3 Maintainer/Contact 5
1.4 Licence 5
1.5 Remarks 5
1.6 Todo 6
2 CGI Basics 7
2.1 Basic CGI Communication 7
2.1.1 Data Input 7
2.1.1.1 CGI independent environment Vars 7
2.1.1.2 CGI dependent Input 7
2.1.1.2.1 the GET Method 7
2.1.1.2.2 the simple POST Method 8
2.1.1.2.3 the multipart/form-data POST Method 8
2.1.2 Data output 9
2.1.2.1 The Header 9
2.1.2.2 The Data 9
2.2 Advanced CGI Programming 9
2.2.1 Cookies 9
2.2.2 Hidden Input Fields 9
2.2.3 Actions 10
2.2.4 Session Keys 10
2.2.5 Databases 10
2.2.6 HTML Templates 10
3 eCgiLib Usage 11
3.1 basics 11
3.1.1 cgiInit() 11
3.1.2 cgiDone() 11
3.1.3 cgiParam() - the main function 11
3.1.4 cgiStrError() 12
3.1.5 Compatibility to version <= 0.5 12
3.2 File Uploads 13
3.2.1 basic concept 13
3.2.2 The filename and the Content-Type 13
3.2.3 3 Kinds of Elements 13
3.2.3.1 cgiKindValue 13
3.2.3.2 cgiKindEmptyFile 13
3.2.3.3 cgiKindFileToBig 14
3.2.3.4 cgiKindFile 14
3.2.4 Accessing the Files 14
3.2.4.1 cgiGetMFile() 14
3.2.4.2 cgiMFileToFile() 14
3.2.5 limits 14
3.2.5.1 cgiSetMaxFileSize() 14
3.2.5.2 cgiSetMaxSize() 14
3.3 Accessing Elements without the knowing the name 15
3.3.1 Why? 15
3.3.2 Access to Elements using cgiGetFirstName() / cgiGetNextName() 15
3.3.3 Access to Elements using cgiPosNext() 15
3.3.4 cgiNameByValue() 16
3.4 Memory Files 16
3.4.1 Basic concept 16
3.4.2 "usual" c file functions and memory files 17
3.4.3 additional memory file functions 17
3.4.3.1 mfMFileToFile() 17
3.4.3.2 mfFileToMFile()/mfFileToMFileN() 17
3.4.3.3 mfGetData() 17
3.4.3.4 mfGetDataAt() 18
3.4.3.5 mfSetLength() 18
3.4.3.6 mfGetLength() 18
3.5 Saving/Loading the environment for simple debugging 18
3.5.1 cgiSaveDebugData() 18
3.5.2 cgiLoadDebugData() 18
3.6 eCgi Toolkit 18
3.6.1 ctkRedirect() 18
3.6.2 ctkGetSessionID() 19
3.6.3 ctkTimeToHDate() 19
3.6.4 ctkHDateToTime() 19
3.7 HTML Preprozessor 19
3.7.1 Basic concept 19
3.7.2 Example 20
3.7.3 Section Tag 23
3.7.4 Param Tag 24
3.7.4 Slink Tag 24
3.7.4 Comments 24
4 eCgiLib Function Library 25
4.1 ecgi.h 25
4.2 memfile.h 26
4.3 ecgi-internal.h - not for the user! 27
Appendix A - Demo Programms 30
A1 Simple-Demo 30
Demo1.html 30
Demo1.c 30
A2 Multi Form Demo / All Data access Demo / Template Demo: 30
html/enter.h 30
html/pageTwo.h 31
html/pageThree.h 31
demo2.c 31
1 Introduction
1.1 What is eCgiLib ?
eCgiLib (= easy CGI Libary) is a simple to use c cgi libary based on cgic. It transparently supports the CGI Method GET and POST and also multipart/form-data file uploads. The user interface is designed as easy as possible and maintains full compatibility to cgic 0.5, from which it is derived
It also contains a libary independend introduction to CGI programming with C, a .html to .h HTML template preprozessor and fast block allocating "memory files"
It was written after needing file upload, searching the web, and finding NO usable c cgi libary, which support all mentioned things AND a easy interface. Course i used cgic 0.5 before, and knew Todor Prokopov <koprok@newmail.net> stopped developing it further, i used his work - and his multipart tests, which he send me. Thanks man!
1.2 History
*****************
* NOW TESTED ON *
*****************
- linux glibc 2.1 gcc 2.95.2
- solaris7 gcc 2.95.2
***********************
* SOURCE CODE CHANGES *
***********************
0.6.2
-----
- added comments headers to files - juhuu!
- copied gpl to doc/COPYING
- fixed bug in html2h - input files where also parsed in comments
13.02.2001
- there was only ONE untouched function from cgic 0.5 left in my ecgi lib,
and this bastard function had an segfault in it (which occured only
VERY rarely) - thanks to "Bao C. Ha" <bao@hacom.net> for showing me.
(who also maintains a ecgi debian package now ...)
- fixed a bug in memfile.h, where i used a "va_list *ap" instead of a
"va_list ap" - how silly ...
thanks to Ramon Poca <ramon@tau.uab.es> for telling me
- ecgitk uses time.h - added an "#include <time.h>", so you dont have to
include it in your programm
0.6.1
------
08.12.2000
- compiled now on solaris - fixed some segfaulting typecasts.
- added: html2h preprozessor now finds HTML input tags and adds them to
the .h header - so you allways know, what names to ask for with cgiParam(),
when getting input from a template
- "ANSI-CLEANED" the sources by changing some things after invoking gcc
with -ansi and -pedantic - changed all // to /* .. */ - ANSI-PROVED now :)
- cleaned up Makefile - ie: if the "gcc --shared" fails now, this happens
as the last thing - should not make any real problems, since libecgi.a
should be generated then
- replaced setenv() with putenv() in loadDebugData(), because setenv is not
supported on solaris (why ever)
- read basics about "autoconf" and decided NOT to do this myself, since my
focus is c-programming!
0.6 Initial Release
-------------------
December 2000
- rewrote complete source from Todor Prokopov - only 1 untouched function
in the sources - added new functions for file handling, for accessing all
objects without the name and saving/loading the whole environment for
debugging.
06.12.2000
- added mfFileToMFileN()
- cgiLoadDebugData() and cgiSaveDebugData() functions work now
- mfprintf() added to memory files
- added "make install" to the Makefile (it creates a .a ar
archive and a .so lib now)
- html2h preprozessor added
- added first functions to ecgitk - eCgiToolkit
*************************
* Documentation Changes *
*************************
13.02.2000
- added example to cgiInit() documentation, since i got an email with a
segfault while calling the cgi from bash
06.12.2000
- documented mfFileToMFileN() - see 3.4.3.2
- updated cgiLoadDebugData() and cgiSaveDebugData() documentation (3.5.1 and 3.5.2)
- added mfprintf() without further documentation to 3.4.2
- updated chapter 3.6 ecgi Toolkit
- added chapter 3.7 html2h HTML preprozessor
December 2000
- wrote first version
1.3 Maintainer/Contact
Thats me! Sven Dawitz - Sven@Dawitz.de. The web adress for ecgi is http://www.Global-OWL.de/ecgi
If you want to contact me, feel free to do so!
1.4 Licence
This Software is under GPL. Blah Blah Blah ...
You have the sources. Just do with it, what you want.
It would be nice, if you drop me an email, if you use it. Just to see, who finds it useful. Perhaps i will add a "Used by" section later.
1.5 Remarks
Put this documentation to professional english. Copy Dahl promised me to do so, if he is available for it. So currently, remeber that i am no natural english speaking guy and have my problems with putting it really professional - but the information itself should be ok ...
If someone else, who is naturally speaking english, read this - perhaps you could edit it and fix up my language.
If you try file uploading, but it fails: check your proxy settings - squid for example only allows upload till 1MB at all - to find out, my program doesnt segfault, but isnt even executed took me about 6 hours of work - upside: i rewrote much code for it and made it (hopefully) segfault secure.
1.6 Todo
- check all malloc/realloc calls for returning NULL - memory at end
- really USE maxfilesize and maxsize - currently dont do anything
- implement the cgiSaveDebugData()/cgiLoadDebugData() - currently they write an error to stdout and exit the program ... not good ...
- check error defines - some are obsolete / others must be added
- think about defining max name size due security (a 150mb name would be fun)
- integrate mad sql libary ...
- integrate ecgitk lib
- test if you can use fread/fseek on stdin to speed up reading
doesn work with popen files, so i guess, wont work with stdin, too
but have to check! Block reads would be really nice!
2 CGI Basics
2.1 Basic CGI Communication
2.1.1 Data Input
The user submits Data via the browser to the web server, who calls the program. There are two main kinds of input to our programm:
2.1.1.1 CGI independent environment Vars
The web server sets environment vars, which contain misc information about the client, like "REMOTE_ADDR" for the remote ip adress, "REMOTE_HOST" for the remote hostname, "SCRIPT" for the script name and others. You can get these environment variables with getenv(). Dump the whole environment variables with a little test programm to see more. These are not part of ecgi. (Or at least, most of them). And they are extremly server and browser dependend.
2.1.1.2 CGI dependent Input
This describes the ways, the CGI programm can get input from the user - There are three ways for that.
Ecgilib handles all transparent for you - you dont need to know how that works. This is just info about the things behind ecgilib.
2.1.1.2.1 the GET Method
The data is send in the URL - you might have seen this before:
http://foo.bar/whatever.cgi?field1=this+is+test+data&field2=any%20other%20data
This is a simple Method - and the only method, you can use with links - for the others, you need a real form, with datafields and at least one submit button. So you will need GET when having many links on your page, which all do something else.
The web server puts this data (after the ?) to the environment variable "QUERY_STRING" where ecgilib reads and parses it.
The GET Method is detected by the environment variable REQUEST_METHOD which is set to "GET".
As far as i know, this method has a maximum length somewhere - but i am neither sure, nor do i know, where this limit is. If you know, email me.
2.1.1.2.2 the simple POST Method
The data is encrypted the same way than in the GET Method:
field1=this+is+test+data&field2=any%20other%20data
But the Web Server writes it to STDIN instead of writing it to a environment variable. You need a real form with <FORM ACTION="script.cgi" METHOD="POST"> and a submit button for this method.
The POST Method is detected by the environment variable REQUEST_METHOD set to "POST" and CONTENT_TYPE set to "application/x-www-form-urlencoded".
With using stdin, this method has no limits i am aware of.
2.1.1.2.3 the multipart/form-data POST Method
This method was created, when realizing, that the usual GET/POST methods were not able to send binary data. So multipart/form-data was born, which uses MIME encryption like:
Content-tpye: mulitpart/form-data; boundary=xyz4711
--xyz4711
content-disposition: form-data; name="username"
Joe Blow
--xyz4711
content-disposition: form-data; name="file-upload"; filename="c:\command.com"
Content-Type: unknown/unknown
Binary data here ff 00 xx yy ...
--xyz4711
content-disposition: form-data; name="multiline-field"
This is
The multiline
Field test
--xyz4711--
For Input, STDIN is used again. if we have a <FORM ACTION="script.cgi" METHOD="POST" ENCTYPE="multipart/form-data"> we can use a <INPUT TYPE="FILE" NAME="file"> inside this form to upload any files (text files AND binary files)
The method is detected by the environment variable REQUEST_METHOD set to "POST" and CONTENT_TYPE starting with "multipart/form-data".
2.1.2 Data output
The result from the program is simply sent to stdout - in two parts, which are seperated by an empty line
2.1.2.1 The Header
Without an Header, the webserver will produce an internal server error. The Header has to be at least "Content-Type: text/html" followed by two returns.
In the header, you can set some more items, like telling the browser/proxies not to cache the site, redirecting the browser to another url by a "Location: http://new.url.com", setting cookies and other stuff.
The data submitted in the header is not shown to the user.
Read the HTTP documentation for more info on this.
2.1.2.2 The Data
This is simply the HTML Page itself, which is rendered by the browser and displayed to the user. Use simple HTML syntax here.
2.2 Advanced CGI Programming
This Chapter shortly gives tips for creating larger cgi programs. It is only a short list of items which can be used. It mainly focuses on the fact, that when having two (or more) pages (ie first page like login with username and password, second page enter some data), the programm is called once for any pages submitted - so you have to exchange data between these two pages. If you dont use any technics here, your programm wont know about the username on the second page.
Make sure to read the demo programms which are in the appendix.
2.2.1 Cookies
This is an "old" method - mainly used by javascript programms, which run on the client.
You can use cookies to save data on the client. This is protected by the second domain name, so "www.domain.com" and "shop.domain.com" can access the same cookie, which is marked as "domain.com". They can not access cookies from "other-domain.com".
The data saved is limited to 40k (as far as i remeber).
Since many security problems with cookies were found, the new browsers can be set to ask you for any cookie before accepting it. Some firewalls completly disallow cookies.
So dont use this method if you are not absolutly sure what you are doing.
Remark: Cookies are not yet supported by ecgi. Perhaps a later version will support it in the toolkit.
2.2.2 Hidden Input Fields
A commonly used technic to save data from one form to the next is using hidden input fields like with <input type="hidden" name="username" value="john doe"> or <input type="hidden" name="password" value="secret">. So the data entered on one form will be printed on the other form. You will need hidden input fields for the following methods. There is not disadvantage of using this. Only remeber that a "bad user" might create his own form, which he sends to your server. So check all input.
2.2.3 Actions
If you have one programm, which generates various pages, you must verify, which action is called now. Take a hidden input field like <input type="hidden" name="action" value"3"> for it. If you are in the main function, you can read the action variable, if it is empty, display the enter page, if not, call the function associated with this value. Read the demo in appendix for an simple example.
2.2.4 Session Keys
This is one of the best technics i know of. When the user enters, you assign a unique session id to him. To make it unique, take the time, the remote address and the remote port - this combination must be unique according to tcp/ip.
Format it as characters, so it is a little crypted.
From now on, ALLWAYS keep the session key as a hidden field. So you can fill shoppers, save any other data of this session without cookies. You can also add an expire data, when the session times out - and an expire idle date, when the session times out when the user not longer accesses you (you must update a last access field for this of course - use databases!)
If you use frames/layers generated by your cgi programm, you should redirect him, if he enters. Else, if he hits reload, you could loose his session id.
2.2.5 Databases
Not much to say about it, just: use them! You can use databases extremly well for all kind of cgi. Else, you have to write to tmp files on your own.
2.2.6 HTML Templates
I usually use html templates to write resulting pages. So you dont have html in your sources, where it probably shouldnt be, but only in external html includes. If you wanna change the layout, you dont have to change the sources. Read the demo for an example.
Caution: if you use tables with lists of data, you have to split the html include in something like "head" / "row" / "foot" - or even more. I am currently working on a preprozessor, so you keep your old html files and only add comments for the preprozessor - which generates your .h file from the .html file. This way, you can allways edit your html file with a html editor and dont have to care about the output.
Advanced tip: For big programs, think about putting the templates in a database, too. So you can change the layout without recompiling the source. You can even add an option to let the user change layout while using the program (if you have more than one layout in your database)
3 eCgiLib Usage
3.1 basics
Here i will put the basic command to ecgi. If you dont use File Upload, this is probably all you need - only 3 functions: cgiInit()/cgiDone() at start/end of programm and cgiParam() for accessing the data. Cgic <=0.5 ONLY had these functions. Thats why it was intended by Todor to call it EASY cgi.
3.1.1 cgiInit()
int cgiInit();
Call this function before accessing anything else. It will parse the input from the server to the program and create an internal list of elements. Only call this function once.
The only functions which may be called before cgiInit are cgiSetMaxFileSize() and cgiSetMaxSize() to set the maximum limit of memory used by ecgiLib (see below)
If the init fails for any reson, the function returns false and sets cgi_errno. You can call cgiStrError() then to get the error.
Call it this way. Else, you might get segfaults, when calling the program from the shell directly!
If(cgiInit()!=ECGI_SUCCESS){
printf("ERROR: %s\n", cgiStrError(cgi_errno));
exit(cgi_errno);
}
3.1.2 cgiDone()
void cgiDone();
Call this function before exiting the programm. Will free all memory occupied by cgiInit().
Note: since most unix systems free all used memory of a program, when this program exits, you must not call cgiDone. Depending on the specific unix system, which you use, it might be faster just to exit and let the system free the memory.
3.1.3 cgiParam() - the main function
const char *cgiParam(const char *name);
This will probably be your most called function. I take the explation of Todor Prokopov here, which is very good:
Use the `cgiParam' function to grab the HTML form entry value, with a
given name, for example:
char *color;
...
color = cgiParam("color");
This function returns NULL, if there isn't an entry with the given name,
passed to the program, so after calling it, you should check that:
if (color == NULL)
{
/* There isn't an entry called "color", passed to us. */
...
}
In instances of multiple values, associated with the same entry name, repeated
use of `cgiParam' with the same entry name cycles through all it's values,
associated with the given name. The return of a null pointer indicates the end
of the cycle. If you need to retrieve the first value instance again, you need
to reset the function. Do this by passing a null pointer, as a parameter to it.
For example, let's assume we have the following entries:
fruit=apple
fruit=pear
The first call `cgiParam("fruit")' returns "apple", the second returns
"pear", the third, fourth and so on returns NULL. If you wish to retrieve the
first value ("apple") again, first reset the function by calling
`cgiParam(NULL)', and then the call `cgiParam("fruit")' returns "apple"
again.
The `cgiParam()' function is reset also by invoking it with another entry
name, not the same as that, you have asked the last time. For example if you
have the following entries, passed:
fruit=apple
fruit=pear
vegetables=potato
Invoking `cgiParam("fruit")' for the first time gives "apple", the second
call `cgiParam("vegetables")' returns "potato" and if you call it again like
this `cgiParam("fruit")', you get "apple" again, not "pear"! If you call
`cgiParam("fruit")' one more time, then you get "pear".
NOTE: You should not modify the string returned by `cgiParam'. If you have
to modify it, first copy it to another piece of memory, using `strdup' or
something similar.
3.1.4 cgiStrError()
const char* cgiStrError(int errnum);
call this, if cgiInit() returns false, which indicates an error:
if(cgiInit()==false){
printf("An Error occured: %s", cgiStrError(cgi_errno));
exit(cgi_errno);
}
3.1.5 Compatibility to version <= 0.5
You might have noticed, that the function names changed. For example, cgi_init() now is called cgiInit(). This naming system is used for all functions now. To stay compatible with the old names, there are some precompiler macros. So the old sources still run with the new lib.
Its just, i personally prefer the case separtion for names than the underscore stuff.
3.2 File Uploads
3.2.1 basic concept
The basic concept for fileuploads it NOT to write the files to any temporary directory, but to the memory. This is done, because writing to a directory will probably bring up security problems. Overwriting existing files, files readable for everyone etc. Reading in memory is a problem, too (you could send REAL big files for DOS attacks). Thats, why i implemented a limit (by default unlimited)
Remember once again: If you do a file upload, the memory is free'd as soon as the result is sent to the user again and NOT during the whole session. So memory usage should be no problem. Its in the hands of the programmer (YES, thats you!). eCgi only provides the tools.
Perhaps i will add an option to write them directly to a directory - even i dont see any need for this now.
3.2.2 The filename and the Content-Type
const char *cgiGetCTyp(const char *name);
the filename can be obtained by a simple cgiParam() call - it is treated like a usual value. The content type can be obtained by a cgiGetCType() call.
Note that both - the file name and the content type - are extremly browser dependend. For example an upload of "/etc/passwd" with netscape for linux will result in filename "passwd" content type "text/plain". The upload of "C:\autoexec.bat" with Microsoft Internet Explorer for Windows will result in filename "C:\autoexec.bat" with content-type "dont-remeber-gotta-test:)"
3.2.3 3 Kinds of Elements
With the cgiGetKind() function, you can get the kind of a cgi element by the name. There are four kinds.
3.2.3.1 cgiKindValue
#define CgiKindValue 1
Usual Name/Value Pair send with normal HTML datafields. Just use cgiParam for those.
3.2.3.2 cgiKindEmptyFile
#define CgiKindFileEmpty 3
An Empty file has been sent.
This can have two reasons:
- No File selected by the user.
- The selected file was only 0bytes long
You can probably check this, when checking if a filename is set. If filename is NOT set, there was no file selected. if it is set, the file was 0byte.
Note: this is browser depended - some browsers perhaps wont send a filename in some cases - so you can NOT check, if it is empty or not selected anymore
3.2.3.3 cgiKindFileToBig
#define CgiKindFileToBig 4
the file uploaded has exceeded one of the limits set with the limit functions (see below).
3.2.3.4 cgiKindFile
#define CgiKindFile 2
Here we finally have a real file.
You can get the Memory File with cgiGetMFile() (see below), or you can directly dump the file to a real file with cgiMFileToFile()
3.2.4 Accessing the Files
3.2.4.1 cgiGetMFile()
MFILE* cgiGetMFile(const char *name);
Calling this function with the name as attribute (see cgiParam()) returns a Pointer to the Memory File MFILE* (see below for handling of memoryfiles)
3.2.4.2 cgiMFileToFile()
int cgiMFileToFile(const char *name, const char *fname, const char *fopenmode);
This function writes the file from memory to your local hard disk. Call it with the fname to write to, and the open mode (see "man fopen" for details of openmode)
Note: memory is NOT free'd by this. You must call mfclose to do so.
3.2.5 limits
As mentioned above, you can set limits to the memory used for file uploads to prevent DOS attacks.
Once one of the Limits is overrun, the kind is set to cgiKindFileToBig. The other cgi elements are processed as usual.
3.2.5.1 cgiSetMaxFileSize()
void cgiSetMaxFileSize(int size);
This functions sets the maximum amount of memory used for a single file.
3.2.5.2 cgiSetMaxSize()
void cgiSetMaxSize(int size);
Since a form can have more than one file upload fields, this functions sets the maximum amount of memory which can be used for all file uploads.
3.3 Accessing Elements without the knowing the name
3.3.1 Why?
Some might say: "You allways know the name, course you are the programmer" - right, but there are some cases, you do NOT know them.
Imagine a tool for sending mails (like formmail.pl does) - you can set a hidden filed "needed" which has the names of the fields which may not be empty. If all fields are filled, you send an email to the adress in "mailto". If you can access all elements, you could easily write such a variable tool. Thats only ONE point where i needed these functions in the past.
There are two general ways of accessing the internal list of elements.
3.3.2 Access to Elements using cgiGetFirstName() / cgiGetNextName()
const char* cgiGetFirstName();
const char* cgiGetNextName();
cgiGetFirstName returns the name of the first element - or NULL if no element found - and sets an internal pointer to the last returned name.
CgiGetNextName returns the next - or NULL if there is no next name.
Since you can access all cgi functions by the name, this is one way of getting all elements.
Example:
const char *val;
printf("%s\n", cgiGetFirstName());
while((val=cgiGetNextName())!=NULL)
printf("%s\n", val);
3.3.3 Access to Elements using cgiPosNext()
typedef void CgiPos;
CgiPos* cgiPosNext(CgiPos *lastpos);
const char* cgiPosParam(CgiPos *where);
const char* cgiPosName(CgiPos *where);
int cgiPosGetKind(CgiPos *where);
const char* cgiPosGetCTyp(CgiPos *where);
MFILE* cgiPosGetMFile(CgiPos *where);
int cgiPosMFileToFile(CgiPos *where, const char *fname, const char *fopenmode);
The function cgiPosNext() returns a pointer to the first element if called with parameter NULL, or to the next if you give the last return value.
With the CgiPos *, you can access all the cgi functions like accessing them by name. (In fact, the name functions internally use these functions. So using the CgiPos* pointer might be slightly faster)
An example should show the usage:
CgiPos *p=NULL;
while((p=cgiPosNext(p))!=NULL){
printf("%s : ", cgiPosName(p));
while((val=cgiPosParam(p))!=NULL)
printf("%s ", val);
if(cgiPosGetKind(p)==cgiKindFile)
printf("This is an file!");
printf("\n");
}
3.3.4 cgiNameByValue()
const char* cgiNameByValue(char *value);
This function returns the name of an element by give the value. Might be usefull in some cases. If called multiple, it acts like cgiParam() and returns all names containing this value, returning NULL when not finding any more.
Example:
while((name=cgiNameByValue("test"))!=NULL)
printf("%s\n", name);
3.4 Memory Files
3.4.1 Basic concept
The memoryfiles are not only the representative of the uploaded files, but heavily used internal for dynamic allocation. Since they dont call realloc every added byte, but allocate blocks of bytes (is defined in memfile.h - default=4k Blocks), they are the fast way to dynamic memory.
You can use this files for everything, which requires much allocation like:
char *buf=NULL;
FILE *f=fopen("whatever", "r");
int c, size=0;
While((c=fgetc(f))!=EOF){
buf=realloc(buf, size+1);
buf[size++]=c;
}
In such a case, you should use the memfiles - and their feature of block allocation. This should be faster, since malloc/realloc is commonly slow.
FILE *f=fopen("whatever", "r");
MFILE *mf=mfopen();
int c;
while((c=fgetc(f))!=EOF)
mfputc(c, mf);
Now you can access the data with all the mf-functions.
3.4.2 "usual" c file functions and memory files
MFILE* mfopen();
void mfclose(MFILE *mf);
int mfseek(MFILE *mf, int offset, int whence);
int mftell(MFILE *mf);
int mfeof(MFILE *mf);
int mfread(void *data, int times, int length, MFILE *mf);
int mfwrite(void *data, int times, int length, MFILE *mf);
int mfgetc(MFILE *mf);
int mfputc(unsigned char c, MFILE *mf);
int mfprintf(MFILE *mf, const char *format, ...);
If you are a c-programmer (hope you are, why else you read this ???), you know these functions. They are exactly what the functions without the leading m are - like mfopen() is the pedant to fopen(), mfseek() is the pedant to fseek(). If you dont know them, just read the c documentation (like "man fseek")
Differences:
mfopen() doesnt get any filename, openmode - i think, its obvious why :)
mfclose() free's all memory used by the file - dont access this pointer after mfclose()
3.4.3 additional memory file functions
Since this are not REAL Files, we have some more (usefull?) functions.
3.4.3.1 mfMFileToFile()
int mfMFileToFile(MFILE *mf, FILE *f);
Appends a MFile to a given File Handle.
Use cgiMFileToFile() for simple dumping.
Note: it APPENDS it to the current position of the cursor in the file. (see "man fopen", "man fseek")
3.4.3.2 mfFileToMFile()/mfFileToMFileN()
int mfFileToMFile(FILE *f, MFILE *mf);
int mfFileToMFileN(FILE *f, MFILE *mf, int count);
Appends a File to a given MFile.
Use the mfFileToMFileN(), if you dont want the whole file to be appended.
Note: it APPENDS it to the current position of the cursor in the MFile (see mfseek)
3.4.3.3 mfGetData()
const char* mfGetData(MFILE *mf);
Returns the data of the file. The data is terminated by 0 at the end of the file, so you can use
printf("%s", mfGetData(myfile));
to dump the data. Remeber: if it is a binary file, it might look very ugly.
3.4.3.4 mfGetDataAt()
const char* mfGetDataAt(MFILE *mf, int start);
same as mfGetData(), but only returns data from start byte. String also NULL Terminated.
3.4.3.5 mfSetLength()
int mfSetLength(MFILE *mf, int length);
For resetting a file to 0 bytes, or any other length. This does not free the used memory, if you set it to 0 bytes. Use mfclose()/mfopen() to free memory. If you set the length bigger than old filesize, data is reallocated.
3.4.3.6 mfGetLength()
int mfGetLength(MFILE *mf);
returns the length of the file - so you dont have to get it with
mfseek(mf, 0, SEEK_SET);
size=mftell(mf);
3.5 Saving/Loading the environment for simple debugging
3.5.1 cgiSaveDebugData()
int cgiSaveDebugData(char *fname, char *fopenmode);
Call cgiSaveDebugData() after cgiInit(). This will dump the whole internal list of data plus all the environment variables to a file, which can be later loaded.
3.5.2 cgiLoadDebugData()
int cgiLoadDebugData(char *fname);
Call cgiLoadDebugData() instead of cgiInit() - after calling this, all environment variables and all cgi elements are restored to the state, they have been with cgiInit() when saving the data.
You can now debug your program from the console instead of using a webbrowser.
3.6 eCgi Toolkit
I will add a cgi Toolkit in "ecgitk.h" which is independend from ecgi.h, but includes commonly used functions which you need when programming cgi programms - like creating a unique session key or reading/saving cookies. I will put here functions, which I personally need, or things users request.
3.6.1 ctkRedirect()
int ctkRedirect(const char *format, ...);
This functions redirects the browser to another url. To make this work, you may NOT have printed anything to stdout yet, because this is done with the header.
If you redirect does not start with "http:", the server name is added to the redirect target to make sure the browser propperly shows the new url, since some browsers have problems with this when getting a relativ url.
Example:
ctkRedirekt("%s?action=%d&sessionid=%s", getenv("SCRIPT_NAME"), ActShowList, cgiParam("sessionid"));
3.6.2 ctkGetSessionID()
const char *ctkGetSessionID();
Returns a unique session id build from the time, the remote ip adress and the remote port. Data put to characters to crypt data a little.
Returned value must be free'd with free()
3.6.3 ctkTimeToHDate()
const char *ctkTimeToHDate(time_t time);
Constructs a asci date from the given time. Currently only in DD.MM.YYYY format.
Returned value must be free'd with free()
3.6.4 ctkHDateToTime()
time_t ctkHDateToTime(const char *hdate);
vice versa of ctkTimeToHDate() - returns a time_t record constructed from a input in format DD.MM.YYYY
Retruns 0, if the given date was in wrong format.
3.7 HTML Preprozessor
3.7.1 Basic concept
In the html2h/ subdir, you will find a binary called html2h, which is the first quick version of a html preprozessor. This is my first way of transparently use the html files as .h templates in a c programm AND still having the old .html file, which can be edited in a program like dreamweaver. The problem was, you have to split the html file in various substrings, delete some rows, you need for the layout, but not for the template and adding quick links to the script. Make sure, you read and understand my concept of html templates (2.2.6) and read the example at Appendix A2, which shows the usage of templates.
html2h parses the tags for it - starting with <!--# -, replaces " with \" and replaces % with %%. You need this as input for printf().
3.7.2 Example
Since it is complicate, to explain what html2h does, without seeing it, here an simple example (which is also included in the html2h/ directory)
Input: demo-simple.html
<!--#Section htmlSimpleHead 'Header of Simple demo file'-->
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<form name="form1" method="post" action="<!--#param s script 'Script Name'-->">
<p>Hello <!--#param s name 'Name of logged in User'-->! </p>
<p>Your Phonenumber:
<input type="text" name="phone" value="<!--#param s phone 'Phone Number'-->>
<br>
Select Area:
<select name="areaselect">
<!--#Section htmlSimpleSelectRow 'The select box items - one row for every possible'-->
<option <!--#Param s selected 'Write SELECTED here, if selected'-->><!--#Param 30s katname 'Area Name - bound to right'--></option>
<!--#/*-->
<option>hong kong</option>
<option>japan</option>
<option>home</option>
<!--#*/-->
<!--#Section htmlSimpleSelectBody-->
</select>
</p>
<p>Current Numbers:</p>
<table width="400" border="0" cellpadding="4">
<tr>
<td>Number</td>
<td>Area</td>
<td>
<div align="center">Delete</div>
</td>
<td>
<div align="center">Edit</div>
</td>
</tr>
<!--#Section htmlSimplePhoneRow 'This lists all existing entries'-->
<tr>
<td><!--#param s number 'Phone Number as string'--></td>
<td><!--#param s area 'Area of number'--></td>
<td>
<div align="center"><a href="<!--#SLink 'Link to Delete Entry' s skey 'Session ID' d eid 'ID of the specific entry'-->">->X<-</a></div>
</td>
<td>
<div align="center"><a href="<!--#SLink 'Link to Edit this Entry' s skey 'Session ID' d eid-->->X<-</a></div>
</td>
</tr>
<!--#Section htmlSimpleFoot-->
<!--#/*-->
<tr>
<td>234233</td>
<td>Home</td>
<td>
<div align="center"><a href="x">->X<-</a></div>
</td>
<td>
<div align="center"><a href="x">->X<-</a></div>
</td>
</tr>
<tr>
<td>342523</td>
<td>japan</td>
<td>
<div align="center"><a href="x">->X<-</a></div>
</td>
<td>
<div align="center"><a href="x">->X<-</a></div>
</td>
</tr>
<!--#*/-->
</table>
<p>
<input type="submit" name="Submit" value="Submit">
<input type="reset" name="Submit2" value="Reset">
</p>
</form>
</body>
</html>
Output: demo-simple.h
/****************************************************
* Header file generated with html2h 0.1 *
* (c) 2000 by Sven@Dawitz.de *
****************************************************
----------------------------------------
htmlSimpleHead "Header of Simple demo file"
----------------------------------------
FORMAT NAME COMMENT
----------------------------------------
s script "Script Name"
s name "Name of logged in User"
s phone "Phone Number"
----------------------------------------
htmlSimpleSelectRow "The select box items - one row for every possible"
----------------------------------------
FORMAT NAME COMMENT
----------------------------------------
s selected "Write SELECTED here, if selected"
30s katname "Area Name - bound to right"
----------------------------------------
htmlSimpleSelectBody
----------------------------------------
FORMAT NAME COMMENT
----------------------------------------
----------------------------------------
htmlSimplePhoneRow "This lists all existing entries"
----------------------------------------
FORMAT NAME COMMENT
----------------------------------------
s number "Phone Number as string"
s area "Area of number"
***SCRIPT LINK*** "Link to Delete Entry"
s script "Script Name"
s skey "Session ID"
d eid "ID of the specific entry"
***SCRIPT LINK*** "Link to Edit this Entry"
s script "Script Name"
s skey "Session ID"
d eid
----------------------------------------
htmlSimpleFoot
----------------------------------------
FORMAT NAME COMMENT
----------------------------------------
****************************************************/
const char htmlSimpleHead[]="
<html>
<head>
<title>Untitled Document</title>
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=iso-8859-1\">
</head>
<body bgcolor=\"#FFFFFF\" text=\"#000000\">
<form name=\"form1\" method=\"post\" action=\"%s\">
<p>Hello %s! </p>
<p>Your Phonenumber:
<input type=\"text\" name=\"phone\" value=\"%s>
<br>
Select Area:
<select name=\"areaselect\">
";
const char htmlSimpleSelectRow[]="
<option %s>%30s</option>
";
const char htmlSimpleSelectBody[]="
</select>
</p>
<p>Current Numbers:</p>
<table width=\"400\" border=\"0\" cellpadding=\"4\">
<tr>
<td>Number</td>
<td>Area</td>
<td>
<div align=\"center\">Delete</div>
</td>
<td>
<div align=\"center\">Edit</div>
</td>
</tr>
";
const char htmlSimplePhoneRow[]="
<tr>
<td>%s</td>
<td>%s</td>
<td>
<div align=\"center\"><a href=\"%s?skey=%s&eid=%d\">->X<-</a></div>
</td>
<td>
<div align=\"center\"><a href=\"%s?skey=%s&eid=%d->X<-</a></div>
</td>
</tr>
";
const char htmlSimpleFoot[]="
</table>
<p>
<input type=\"submit\" name=\"Submit\" value=\"Submit\">
<input type=\"reset\" name=\"Submit2\" value=\"Reset\">
</p>
</form>
</body>
</html>
";
3.7.3 Section Tag
<!--#section name ['comment']-->
The section tag will create a const char name[] entry for every section generated. You need a section before any html data. The comment is optional.
<!--#section htmlHead 'this is just a demo'-->
html stuff here
<!--#section htmlRow 'this is the next row'-->
would result in
const char htmlHead[]="
html stuff here
";
const char htmlRow[]="...
3.7.4 Param Tag
<!--#param format name ['comment']-->
format is a printf format.
<!--#param 10.3f floatvar-->
would result in
%10.3f
3.7.4 Slink Tag
<!--#slink format name1 ['comment'] format name2 ['comment'] ... format name3 ['comment'] -->
Use this, if you link to the script with varous parameters.
<!--#slink s skey 'session ID' d action 'ActShowStats' s user-->
would result in
%s?skey=%s&action=%d&user=%s
3.7.4 Comments
<!--#/*--> not printed in .h file <!--#*/-->
These are the comment tags - link in c. html2h supports multi nested comments.
4 eCgiLib Function Library
Here are the header files of ecgi lib. The Usage should be obvious after reading chapter 3.
4.1 ecgi.h
The only file you need to include from your programm. Auto includes memfile.h, course you need it, too.
#define CgiKindValue 1
#define CgiKindFile 2
#define CgiKindFileEmpty 3
typedef void CgiPos;
/****************************************
* OLD FUNCTION NAMES FOR COMPATIBILITY *
****************************************/
#define cgi_init() cgiInit()
#define cgi_param(name) cgiParam(name)
#define cgi_done() cgiDone()
#define cgi_strerror(no) cgiStrError(no)
/*****************************************
* TRADITIONAL FUNCTIONS OF OLD CGIC 0.5 *
*****************************************/
int cgiInit();
const char* cgiParam(const char *name);
void cgiDone();
const char* cgiStrError(int errnum);
/*******************************
* NEW FILE DEPENDED FUNCTIONS *
*******************************/
void cgiSetMaxFileSize(int size);
void cgiSetMaxSize(int size);
int cgiGetKind(const char *name);
const char* cgiGetCTyp(const char *name);
MFILE* cgiGetMFile(const char *name);
int cgiMFileToFile(const char *name, const char *fname, const char *fopenmode);
/****************************
* MISC OTHER NEW FUNCTIONS *
****************************/
const char* cgiNameByValue(char *value);
/**********************************************************
* FUNCTION FOR GETTING ALL DATA WITHOUT KNOWING THE NAME *
**********************************************************/
const char* cgiGetFirstName();
const char* cgiGetNextName();
CgiPos* cgiPosNext(CgiPos *lastpos);
const char* cgiPosParam(CgiPos *where);
const char* cgiPosName(CgiPos *where);
int cgiPosGetKind(CgiPos *where);
const char* cgiPosGetCTyp(CgiPos *where);
MFILE* cgiPosGetMFile(CgiPos *where);
int cgiPosMFileToFile(CgiPos *where, const char *fname, const char *fopenmode);
/*****************************************************************
* FUNCTIONS FOR SAVING/LOADING ENVIRONMENT - GOOD FOR DEBUGGING *
*****************************************************************/
int cgiSaveDebugData(char *fname, char *fopenmode);
int cgiLoadDebugData(char *fname);
/* the error number */
extern int cgi_errno;
4.2 memfile.h
This is the interface for the memory files. Again: should be compatible with the usual f-functions.
#define MFILE_BLOCK 4096 // in what block should mem be increased
#ifndef true
#define true (1==1)
#define false (0==1)
#endif
typedef struct S_MFILE{
void *data;
int blocks;
int eof;
int used;
int pos;
}MFILE;
/**************************************************************
* FUNCTIONS 100% COMPATIBLE WITH USUAL F* FUNCTIONS - I HOPE *
**************************************************************/
MFILE* mfopen();
void mfclose(MFILE *mf);
int mfseek(MFILE *mf, int offset, int whence);
int mftell(MFILE *mf);
int mfeof(MFILE *mf);
int mfread(void *data, int times, int length, MFILE *mf);
int mfwrite(void *data, int times, int length, MFILE *mf);
int mfgetc(MFILE *mf);
int mfputc(unsigned char c, MFILE *mf);
/************************
* ADDITIONAL FUNCTIONS *
************************/
int mfMFileToFile(MFILE *mf, FILE *f);
int mfFileToMFile(FILE *f, MFILE *mf);
const char* mfGetData(MFILE *mf);
const char* mfGetDataAt(MFILE *mf, int start);
int mfSetLength(MFILE *mf, int length);
int mfGetLength(MFILE *mf);
4.3 ecgi-internal.h - not for the user!
you should not use this file - this is the part which is used internal, but "hidden" to the user - if you have any reason to include this file, i might have forgotten something.
Note: this file and the internal list of cgi elements might be changed later. The user interface of ecgi.h will not be changed. So you are compatible to following versions with ecgi.h - with ecgi-internal.h you might be not!
/***********************************************
* THE STRUCTS/LIST WE STORE THE WHOLE SHIT IN *
***********************************************/
typedef struct _CgiValue{
char *value;
struct _CgiValue *next;
}CgiValue;
typedef struct _CgiElement {
int type;
char *name;
char *ctyp;
CgiValue *values;
MFILE *mf;
struct _CgiElement *next;
}CgiElement;
typedef struct _CGI{
CgiElement *list;
CgiElement *lastasked;
CgiValue *lastret;
CgiElement *lastvalasked;
CgiElement *lastnameasked;
}Cgi;
/********************************
* INTERNAL FUNCTION PROTOTYPES *
********************************/
// List Stuff
int listAddData(int type, const char *name, const char *value, const char *ctyp, MFILE *mf);
CgiElement *listGetByName(const char *name);
CgiElement *listAppendElement(int type, const char *name, const char *ctyp, MFILE *mf);
CgiValue *listAppendValue(CgiElement *where, const char *value);
int listHasValue(CgiElement *check, char *value);
void listFreeAll();
void listDump(); // for test usage only ... dumps all vals to stdout ...
// Init/Parse Stuff
int initGet();
int initPost();
int initMultiPart(const char *cont_type);
int parseMultiPart(char *boundary);
int parseMultiHead(char **name, char **fname, char **ctyp);
int parseQueryString(const char *str, int length); // str==NULL - read from stdin
// Misc Help Functions
int miscStringDecode(char *s);
int miscFReadLn(FILE *f, MFILE *mf);
int miscStringToUInt(const char *str, unsigned int *res);
char *miscStringDelCrLf(char *str);
/**********************
* OTHER USELESS SHIT *
**********************/
/* external vars - here for real */
int cgi_errno=0;
/* global vars */
Cgi *c=NULL;
int maxfilesize=-1;
int maxsize=-1;
int init_called=false;
int init_complete=false;
#define NUMERRS 25
static const char *errmsgs[NUMERRS] = {
"Success",
"Unknown request method",
"Repeated initialization attempt",
"Null query string",
"Unknown content type",
"Invalid content length",
"Unexpected end of input stream",
"Input stream read error",
"Maximum entry name length exceeded",
"Maximum entry value length exceeded",
"Invalid URL-encoded data",
"Maximum number of entries exceeded",
"Memory allocation error",
"Maximum memory limit exceeded",
"Invalid boundary string",
"Null file upload directory",
"Pathname length limit exceeded",
"Extremely long line encountered",
"Missing boundary string",
"Error opening file for writing",
"Error writing to file",
"Error closing file",
"Error changing file permissions",
"Missing initial boundary string",
"Error parsing content disposition"
};
#define CGIERR_UREQM 1 /* Unknown request method */
#define CGIERR_REINIT 2 /* Repeated initialization attempt */
#define CGIERR_NULQSTR 3 /* Null query string */
#define CGIERR_UCONTT 4 /* Unknown content type */
#define CGIERR_ICONTLEN 5 /* Invalid content length */
#define CGIERR_UEOINP 6 /* Unexpected end of input stream */
#define CGIERR_INPREAD 7 /* Input stream read error */
#define CGIERR_MAXNAMEE 8 /* Maximum entry name length exceeded */
#define CGIERR_MAXVALE 9 /* Maximum entry value length exceeded */
#define CGIERR_IURLENC 10 /* Invalid URL-encoded data */
#define CGIERR_MAXENTRSE 11 /* Maximum number of entries exceeded */
#define CGIERR_MALLOC 12 /* Memory allocation error */
#define CGIERR_MAXMEME 13 /* Maximum memory limit exceeded */
#define CGIERR_IBSTR 14 /* Invalid boundary string */
#define CGIERR_NULUPLD 15 /* Null file upload directory */
#define CGIERR_PATHMAXE 16 /* Pathname length limit exceeded */
#define CGIERR_LONGLN 17 /* Extremely long line encountered */
#define CGIERR_MBSTR 18 /* Missing boundary string */
#define CGIERR_FOPEN 19 /* Error opening file for writing */
#define CGIERR_FWRITE 20 /* Error writing to file */
#define CGIERR_FCLOSE 21 /* Error closing file */
#define CGIERR_CHMOD 22 /* Error changing file permissions */
#define CGIERR_MBBSTR 23 /* Missing initial boundary string */
#define CGIERR_DISPPARS 24 /* Error parsing content disposition */
Appendix A - Demo Programms
These are two very simple, but working programms which should show the basic use of ecgilib.
A1 Simple-Demo
Demo1.html
<html>
<body><pre>
<form action="demos.cgi" method="post">
Name: <input type=text name="name">
Password: <input type=password name="passwd">
<input type=submit>
</form>
</html>
Demo1.c
#include <stdio.h>
#include <ecgi.h>
int main()
{
cgiInit();
printf("Content-Type: text/html\n\n");
printf("Your name: %s\n", cgiParam("name"));
printf("Your password: %s\n", cgiParam("passwd"));
cgiDone();
return(0);
}
Thats it!
A2 Multi Form Demo / All Data access Demo / Template Demo:
html/enter.h
const char htmlEnter[]="
<html><body><pre>
<form script=\"%s\">
<input type=hidden name=action value=%d>
Your Name: <input type=text name=name>
Your Password: <input type=text name=passwd>
<input type=submit>
</form>
</body></html>
";
html/pageTwo.h
const char htmlPageTwo[]="
<html><body><pre>
<form script=\"%s\">
<input type=hidden name=action value=%d>
<input type=hidden name=\"name\" value=\"%s\">
<input type=hidden name=\"passwd\" value=\"%s\">
Hello %s!
Please Select persons, you wanna kill: <select name=\"to kill\" multiple>
<option>Wife / Girlfriend</option>
<option>Mum and Dad</option>
<option>KILL ALL HUMANS</option>
</select>
Please Enter the amount of Bullets for each person: <input type=text name=bulcount>
<input type=submit value=\"kill em\">
</form>
</body></html>
";
html/pageThree.h
const char htmlPageThreeHead[]="
<html><head><title>Result of your inputs</title></head>
<body>
This is the data send from you:<p>
";
const char htmlPageThreeRowHead[]="
Name: %s <br> Values: <br>
";
const char htmlPageThreeRow[]="
%s <br>
";
const char htmlPageThreeRowFoot[]="
<hr width=90%%>
";
const char htmlPageThreeFoot[]="
<br>Your commands will be executed now!</body></html>";
demo2.c
#include <stdio.h>
#include <stdlib.h>
#include <ecgi.h>
#include "html/enter.h"
#include "html/pageTwo.h"
#include "html/pageThree.h"
#define ActEnter 0
#define ActPageTwo 1
#define ActPageThree 2
void mainEnter();
void mainPageTwo();
void mainPageThree();
const char *script;
int main()
{
int action=0;
const char *saction;
cgi_init();
script=getenv("SCRIPT_NAME");
saction=cgiParam("action");
if(saction!=NULL) action=atoi(saction);
printf("Content-Type: text/html\n\n");
switch(action){
case ActPageTwo: mainPageTwo(); break;
case ActPageThree: mainPageThree(); break;
default: mainEnter(); break;
}
cgiDone();
return(0);
}
void mainEnter()
{
printf(htmlEnter, script, ActPageTwo);
}
void mainPageTwo()
{
printf(htmlPageTwo, script, ActPageThree, cgiParam("name"), cgiParam("passwd"), cgiParam("name"));
}
void mainPageThree()
{
CgiPos *p=NULL;
const char *val;
cgiParam(NULL);
// notice, no need to know any of the names of the fields from above
printf(htmlPageThreeHead);
while((p=cgiPosNext(p))!=NULL){
printf(htmlPageThreeRowHead, cgiPosName(p));
while((val=cgiPosParam(p))!=NULL)
printf(htmlPageThreeRow, val);
printf(htmlPageThreeRowFoot);
}
printf(htmlPageThreeFoot);
}
eCgiLib 0.6 Tutor
Print 02.12.2000 18:10 Seite 5
|