View Source

[modwtcl]
apreq.h
dist/
libapreq1/
mod_wtcl.c
mod_wtcl.h
setupExclude.txt
util/
win.def
win.mak
wt1.1/
WtAppTable.c
WtAppTable.h
WtBasicCmds.c
WtBasicCmds.h
WtClientRequest.c
WtClientRequest.h
WtCollection.c
WtCollection.h
WtCollectionCmds.c
WtCollectionCmds.h
WtContext.c
WtContext.h
WtContextEvents.c
WtContextEvents.h
WtCookie.c
WtCookie.h
WtDbSession.c
WtDbSession.h
WtExecute.c
WtExecute.h
WtHtmlEntities.c
WtHtmlEntities.h
WtInitCmds.c
WtInitCmds.h
WtMtTable.c
WtMtTable.h
WtMultiTable.c
WtMultiTable.h
WtOS.h
WtProcSession.c
WtProcSession.h
WtResponse.c
WtResponse.h
WtServerCmds.c
WtServerCmds.h
WtSession.c
WtSession.h
WtSettings.c
WtSettings.h
WtTable.c
WtTable.h
WtTableCmds.c
WtTableCmds.h
WtTableUtil.c
WtTableUtil.h
WtUpload.c
WtUpload.h
WtUtil.c
WtUtil.h
WtWebErrors.c
WtWebErrors.h
WtWindows.h
File: / archive / modwtcl / WtResponse.c

Lines Size Modified Created Owner MIME Types
490 11,414 2010/05/08 18:46:41 2011/06/13 15:35:15 BUILTIN\Administrators text/x-csrc

0001
/*
0002
 * Copyright 2001 Alexander Boverman and the original authors.
0003
 * 
0004
 * Licensed under the Apache License, Version 2.0 (the "License");
0005
 * you may not use this file except in compliance with the License.
0006
 * You may obtain a copy of the License at
0007
 * 
0008
 *      http://www.apache.org/licenses/LICENSE-2.0
0009
 * 
0010
 * Unless required by applicable law or agreed to in writing, software
0011
 * distributed under the License is distributed on an "AS IS" BASIS,
0012
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013
 * See the License for the specific language governing permissions and
0014
 * limitations under the License.
0015
 */
0016
0017
#include "WtResponse.h"
0018
#include "WtUtil.h"
0019
#include "WtCookie.h"
0020
#include "WtCollection.h"
0021
#include "WtTable.h"
0022
#include "WtTableUtil.h"
0023
#include "WtBasicCmds.h"
0024
#include "WtMultiTable.h"
0025
#include "WtWebErrors.h"
0026
0027
/*
0028
 * Web output channel
0029
 */
0030
0031
static int WtOutBlockModeProc(ClientData instanceData, int mode)
0032
{
0033
  return 0;
0034
}
0035
0036
static int WtOutCloseProc(ClientData instanceData, Tcl_Interp *interp)
0037
{
0038
  /* Free channel data */
0039
  return 0;
0040
}
0041
0042
static int WtOutInputProc(ClientData instanceData, char *buf, int bufSize, int *errorCodePtr)
0043
{
0044
  /* Not implemented */
0045
  *errorCodePtr = EINVAL;
0046
  return -1;
0047
}
0048
0049
static int WtOutOutputProc(ClientData instanceData, const char *buf, int toWrite,
0050
  int *errorCodePtr)
0051
{
0052
  WtContext *w = (WtContext *)instanceData;
0053
0054
  if (WtHeadersSent(w) || WtSendHeaders(w, w->web->apReq, w->web->interp)) {
0055
    if (toWrite) {
0056
      ap_rwrite(buf, toWrite, w->web->apReq);
0057
      ap_rflush(w->apReq);
0058
      w->web->clientResponse.bytesSent += toWrite;
0059
      WtLog(HERE, APLOG_DEBUG | APLOG_NOERRNO, w,
0060
        "Wtcl: Wrote %d bytes to output stream. Total written: %lu.",
0061
        toWrite, w->web->clientResponse.bytesSent);
0062
    }
0063
    return toWrite;
0064
  } else {
0065
    *errorCodePtr = EINVAL;
0066
  }
0067
0068
  return -1;
0069
}
0070
0071
static int WtOutSetOptionProc(ClientData instanceData, Tcl_Interp *interp,
0072
    const char *optionName, const char *newValue)
0073
{
0074
  return Tcl_BadChannelOption(interp, optionName, NULL);
0075
}
0076
0077
static void WtOutWatchProc(ClientData instanceData, int mask)
0078
{
0079
  /* Select on output handle */
0080
}
0081
0082
static int WtOutGetHandleProc(ClientData instanceData, int direction,
0083
    ClientData *handlePtr)
0084
{
0085
  /* Not implemented */
0086
  return TCL_ERROR;
0087
}
0088
0089
Tcl_ChannelType WtOutChanType = {
0090
  "web",
0091
  TCL_CHANNEL_VERSION_2,
0092
  WtOutCloseProc,
0093
  WtOutInputProc,
0094
  WtOutOutputProc,
0095
  NULL,
0096
  WtOutSetOptionProc,
0097
  NULL,
0098
  WtOutWatchProc,
0099
  WtOutGetHandleProc,
0100
  NULL,
0101
  NULL,
0102
  NULL,
0103
  NULL,
0104
  NULL,
0105
  NULL
0106
};
0107
0108
int WtLoadResponseCookies(WtContext *w)
0109
{
0110
  int ok = 1, size, i, j, len, intVal;
0111
  Tcl_Obj *cookieStore, *cookie, *val, *obj;
0112
  ApacheCookie *apCookie;
0113
  Tcl_Interp *interp = w->web->interp;
0114
0115
  cookieStore = w->web->clientResponse.cookies;
0116
  if (!WtClnSize(cookieStore, &size, interp)) {
0117
    return 0;
0118
  }
0119
0120
  for (i = 0; i < size; i++) {
0121
    if (!WtGetClnItemAtIndex(cookieStore, i, &cookie, interp)) {
0122
      ok = 0;
0123
      break;
0124
    }
0125
0126
    if (!WtConvertToTable(cookie, interp)) {
0127
      ok = 0;
0128
      break;
0129
    }
0130
0131
    apCookie = ApacheCookie_new(w->web->apReq, NULL);
0132
0133
    /* Name */
0134
0135
    if (!(val = WtCookieGetName(cookie, interp))) {
0136
      ok = 0;
0137
      break;
0138
    }
0139
0140
    apCookie->name = ap_pstrdup(w->web->apReq->pool, WtToString(val));
0141
0142
    /* Values */
0143
0144
    if (!WtCookieGetAllValues(cookie, &val, interp)) {
0145
      ok = 0;
0146
      break;
0147
    }
0148
0149
    if (Tcl_ListObjLength(w->web->interp, val, &len) !=
0150
        TCL_OK) {
0151
      ok = 0;
0152
      break;
0153
    } else {
0154
      for (j = 0; j < len; j++) {
0155
        if (Tcl_ListObjIndex(NULL, val, j, &obj) !=
0156
            TCL_OK) {
0157
          ok = 0;
0158
          break;
0159
        }
0160
        ApacheCookieAdd(apCookie, WtSafeStr(WtToString(obj)));
0161
      }
0162
      if (!ok) {
0163
        break;
0164
      }
0165
    }
0166
0167
    /* Expiration */
0168
0169
    if (!(val = WtCookieGetExpires(cookie, interp))) {
0170
      ok = 0;
0171
      break;
0172
    }
0173
0174
    apCookie->expires = ap_pstrdup(w->web->apReq->pool,
0175
      WtSafeStr(WtToString(val)));
0176
0177
    /* Domain */
0178
0179
    if (!(val = WtCookieGetDomain(cookie, interp))) {
0180
      ok = 0;
0181
      break;
0182
    }
0183
0184
    apCookie->domain = ap_pstrdup(w->web->apReq->pool,
0185
      WtSafeStr(WtToString(val)));
0186
0187
    /* Path */
0188
0189
    if (!(val = WtCookieGetPath(cookie, interp))) {
0190
      ok = 0;
0191
      break;
0192
    }
0193
0194
    apCookie->path = ap_pstrdup(w->web->apReq->pool,
0195
      WtSafeStr(WtToString(val)));
0196
0197
    /* Secure */
0198
0199
    if (!(val = WtCookieGetSecure(cookie, interp)) ||
0200
        Tcl_GetBooleanFromObj(interp, val, &intVal) != TCL_OK) {
0201
      ok = 0;
0202
      break;
0203
    }
0204
0205
    apCookie->secure = intVal;
0206
0207
    /* Set header */
0208
0209
    ApacheCookie_bake(apCookie);
0210
  }
0211
0212
  return ok;
0213
}
0214
0215
/* Have the headers been flushed */
0216
0217
int WtHeadersSent(WtContext *w)
0218
{
0219
  return w->web->clientResponse.headersStatus == WT_STATUS_OK;
0220
}
0221
0222
/* Flush the headers */
0223
0224
int WtSendHeaders(WtContext *w, request_rec *apReq, Tcl_Interp *interp)
0225
{
0226
  int ok = 1;
0227
0228
  if (w->web->clientResponse.headersStatus != WT_STATUS_NONE) {
0229
    ok = w->web->clientResponse.headersStatus == WT_STATUS_OK;
0230
  } else if (!WtSetApHeaders(w, interp)) {
0231
    w->web->clientResponse.headersStatus = WT_STATUS_ERROR;
0232
    ok = 0;
0233
  } else {
0234
    apReq->status = w->web->clientResponse.status;
0235
    ap_send_http_header(apReq);
0236
    w->web->clientResponse.headersStatus = WT_STATUS_OK;
0237
  }
0238
0239
  return ok;
0240
}
0241
0242
/* Send apache headers */
0243
0244
int WtSendApHeaders(request_rec *apReq)
0245
{
0246
  if (!apReq->content_type || !*(apReq->content_type)) {
0247
    apReq->content_type = "text/html";
0248
  }
0249
  ap_send_http_header(apReq);
0250
0251
  return 1;
0252
}
0253
0254
/* Fill apache headers */
0255
0256
int WtSetApHeaders(WtContext *w, Tcl_Interp *interp)
0257
{
0258
  int ok = 1;
0259
  char *ctype;
0260
0261
  /* Get content type */
0262
0263
  if (!WtOwnCaselessTable(&w->web->clientResponse.headers, interp)) {
0264
    if (!w->web->pageIsStarted) {
0265
      WtInterpError(HERE, w, w->web->interp);
0266
    }
0267
    ok = 0;
0268
  } else {
0269
    WtTableRemoveStr(w->web->clientResponse.headers, "Content-Type");
0270
    if (!WtOwnCaselessTable(&w->web->clientResponse.successHeaders,
0271
        interp)) {
0272
      if (!w->web->pageIsStarted) {
0273
        WtInterpError(HERE, w, w->web->interp);
0274
      }
0275
      ok = 0;
0276
    } else {
0277
      WtTableRemoveStr(w->web->clientResponse.successHeaders,
0278
        "Content-Type");
0279
    }
0280
  }
0281
0282
  if (ok) {
0283
    ctype = WtToString(w->web->clientResponse.contentType);
0284
0285
    if (ctype && *ctype) {
0286
      w->web->apReq->content_type =
0287
        ap_pstrdup(w->web->apReq->pool, ctype);
0288
    } else {
0289
      w->web->apReq->content_type = "text/html";
0290
    }
0291
0292
    /* Fill apache tables */
0293
0294
    if (!WtUpdateApFromLVTable(w->web->apReq->err_headers_out,
0295
        w->web->clientResponse.headers,
0296
        w->web->interp)) {
0297
      if (!w->web->pageIsStarted) {
0298
        WtInterpError(HERE, w, w->web->interp);
0299
      }
0300
      ok = 0;
0301
    }
0302
  }
0303
0304
  if (ok && !WtUpdateApFromLVTable(w->web->apReq->headers_out,
0305
      w->web->clientResponse.successHeaders, w->web->interp)) {
0306
    if (!w->web->pageIsStarted) {
0307
      WtInterpError(HERE, w, w->web->interp);
0308
    }
0309
    ok = 0;
0310
  }
0311
0312
  if (ok && !WtLoadResponseCookies(w)) {
0313
    ok = 0;
0314
  }
0315
0316
  return ok;
0317
}
0318
0319
/* Write response data */
0320
0321
int WtWriteResponse(char *bytes, int len, WtContext *w)
0322
{
0323
  if (bytes) {
0324
    if (len == -1) {
0325
      len = strlen(bytes);
0326
    }
0327
    if (len && Tcl_Write(w->webChannel, bytes, len) == -1) {
0328
      return 0;
0329
    }
0330
  }
0331
0332
  return 1;
0333
}
0334
0335
/* contentType command */
0336
0337
int WtContentTypeCmd(ClientData clientData, Tcl_Interp *interp,
0338
    int objc, Tcl_Obj *const objv[])
0339
{
0340
  int ret = TCL_ERROR;
0341
  WtContext *w = WtGetAssocContext(interp);
0342
0343
  if (objc != 1 && objc != 2) {
0344
    Tcl_AppendResult(interp, wtBadUsagePrefix,
0345
      WtToString(objv[0]), " ?contentType?", NULL);
0346
  } else if (objc == 1) {
0347
    Tcl_SetObjResult(interp, w->web->clientResponse.contentType);
0348
    ret = TCL_OK;
0349
  } else {
0350
    Tcl_DecrRefCount(w->web->clientResponse.contentType);
0351
    w->web->clientResponse.contentType = objv[1];
0352
    Tcl_IncrRefCount(w->web->clientResponse.contentType);
0353
    Tcl_SetObjResult(interp, w->web->clientResponse.contentType);
0354
    ret = TCL_OK;
0355
  }
0356
0357
  return ret;
0358
}
0359
0360
/* responseHeaders command */
0361
0362
int WtResponseHeadersCmd(ClientData clientData, Tcl_Interp *interp,
0363
    int objc, Tcl_Obj *const objv[])
0364
{
0365
  int ret;
0366
  WtContext *w = WtGetAssocContext(interp);
0367
0368
  int status = WtMultiTableMethodHelper(clientData, interp, objc,
0369
    objv, &ret, &w->web->clientResponse.headers,
0370
    &WtCaselessTableType, 0, 1);
0371
0372
  return ret;
0373
}
0374
0375
/* successHeaders command */
0376
0377
int WtSuccessHeadersCmd(ClientData clientData, Tcl_Interp *interp,
0378
    int objc, Tcl_Obj *const objv[])
0379
{
0380
  int ret;
0381
  WtContext *w = WtGetAssocContext(interp);
0382
0383
  int status = WtMultiTableMethodHelper(clientData, interp, objc,
0384
    objv, &ret, &w->web->clientResponse.successHeaders,
0385
    &WtCaselessTableType, 0, 1);
0386
0387
  return ret;
0388
}
0389
0390
/* sendHeaders command */
0391
0392
int WtSendHeadersCmd(ClientData clientData, Tcl_Interp *interp,
0393
    int objc, Tcl_Obj *const objv[])
0394
{
0395
  int ret = TCL_ERROR;
0396
  WtContext *w = WtGetAssocContext(interp);
0397
0398
  if (WtHeadersSent(w) || WtSendHeaders(w, w->web->apReq, w->web->interp)) {
0399
    ret = TCL_OK;
0400
  }
0401
0402
  return ret;
0403
}
0404
0405
/* status command */
0406
0407
int WtStatusCmd(ClientData clientData, Tcl_Interp *interp,
0408
    int objc, Tcl_Obj *const objv[])
0409
{
0410
  int ret = TCL_ERROR, status;
0411
  WtContext *w = WtGetAssocContext(interp);
0412
0413
  if (objc != 2 && objc != 3) {
0414
    Tcl_AppendResult(interp, wtBadUsagePrefix,
0415
      Tcl_GetString(objv[0]), " ?status?", NULL);
0416
  } else {
0417
    if (objc == 2) {
0418
      if (Tcl_GetIntFromObj(interp, objv[1], &status) == TCL_OK) {
0419
        w->web->clientResponse.status = status;
0420
        Tcl_SetObjResult(interp,
0421
          Tcl_NewIntObj(w->web->clientResponse.status));
0422
        ret = TCL_OK;
0423
      }
0424
    } else if (objc == 3) {
0425
      Tcl_SetObjResult(interp,
0426
        Tcl_NewIntObj(w->web->clientResponse.status));
0427
    }
0428
  }
0429
0430
  return ret;
0431
}
0432
0433
/* redirect command */
0434
0435
int WtRedirectCmd(ClientData clientData, Tcl_Interp *interp,
0436
    int objc, Tcl_Obj *const objv[])
0437
{
0438
  int ret = TCL_OK, status;
0439
  WtContext *w = WtGetAssocContext(interp);
0440
  Tcl_Obj *key;
0441
0442
  if (objc == 2 || objc == 3) {
0443
    if (!WtOwnTableObj(&w->web->clientResponse.headers,
0444
        &WtCaselessTableType, interp)) {
0445
      ret = TCL_ERROR;
0446
    } else {
0447
      status = 302;
0448
      if (objc == 3 && Tcl_GetIntFromObj(interp, objv[2], &status) != TCL_OK) {
0449
        ret = TCL_ERROR;
0450
      } else {
0451
        key = WtNewString("Location");
0452
        Tcl_IncrRefCount(key);
0453
        WtTableSetOneValueList(w->web->clientResponse.headers,
0454
          key, objv[1], NULL);
0455
        Tcl_DecrRefCount(key);
0456
0457
        w->web->clientResponse.status = status;
0458
      }
0459
    }
0460
  } else {
0461
    Tcl_AppendResult(interp, wtBadUsagePrefix,
0462
      Tcl_GetString(objv[0]), " location ?status?", NULL);
0463
    ret = TCL_ERROR;
0464
  }
0465
0466
  return ret;
0467
}
0468
0469
/* Initialize response commands */
0470
0471
void WtInitResponseCommands(Tcl_Interp *interp)
0472
{
0473
  Tcl_CreateObjCommand(interp, "::wt::response::contentType",
0474
    WtContentTypeCmd, NULL, NULL);
0475
0476
  Tcl_CreateObjCommand(interp, "::wt::response::headers",
0477
    WtResponseHeadersCmd, NULL, NULL);
0478
0479
  Tcl_CreateObjCommand(interp, "::wt::response::successHeaders",
0480
    WtSuccessHeadersCmd, NULL, NULL);
0481
0482
  Tcl_CreateObjCommand(interp, "::wt::response::sendHeaders",
0483
    WtSendHeadersCmd, NULL, NULL);
0484
0485
  Tcl_CreateObjCommand(interp, "::wt::response::status",
0486
    WtStatusCmd, NULL, NULL);
0487
0488
  Tcl_CreateObjCommand(interp, "::wt::response::redirect",
0489
    WtRedirectCmd, NULL, NULL);
0490
}