分享

悲催的idhttpServer Get Post Upload 上传 multipart form post

 quasiceo 2014-08-24
悲催的idhttpServer.

Get  浏览网页

编码问题.明明网页中有chaset,但中文仍然显示为乱码.

必须在 ContentType中指定 chaset,
AResponseInfo.CharSet 设置无效???

      contentType := GetMimeTypeFromFile(LocalDoc);
        if LeftStr(ContentType, 4) = 'text' then
        begin
          ContentType := ContentType + '; charset=gb2312';
        end;
        AResponseInfo.ContentType := contentType;

AResponseInfo.ContentText 指定为含有中文的字符串,会显示乱码.
用流.

    AResponseInfo.ResponseNo := 404;
    AResponseInfo.ContentType := 'text/plain' + '; charset=gb2312';
    //乱码须用流的形式
    {memoryStream:=TMemoryStream.Create;
    s:='找不到' + ARequestInfo.Document;
    memorystream.write(PAnsichar(s)^,length(s));
    AResponseInfo.ContentStream := memorystream; }
    AResponseInfo.ContentText :=
      '<html>' + #13#10 +
      '<body>' + #13#10 +
      'Page not found:<br>' + #13#10 +
      '<b>' + ARequestInfo.Document + '</b>' + #13#10 +
      '</body>' + #13#10 +
      '</html>';

对于存在的文件,用 AResponseInfo.ServeFile(AContext, rPage)来试试看.可能可以避免乱码,未实验,估计可行?

procedure TfrmMain.ServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  rPage : String;
begin
  Log('Serving: ' + ARequestInfo.Document + ' to ' + AContext.Connection.Socket.Host, clBlue);
  if (ARequestInfo.Document <> '') and
     (ARequestInfo.Document <> '/') and
     (ARequestInfo.Document <> '\') then
    rPage := Copy(ARequestInfo.Document, 2, Length(ARequestInfo.Document))
  else
    rPage := 'Index.htm';
  rPage := StringReplace(rPage, '/', '\',[rfReplaceAll, rfIgnoreCase]);
  rPage := IncludeTrailingBackslash(edServerRoot.Text) + rPage;
  if FileExists(rPage) then
    AResponseInfo.ServeFile(AContext, rPage)
  else
    AResponseInfo.ContentText := '<H1>ERROR</H1>File not found: '+ARequestInfo.Document;
end;

Post上传文件.
procedure TForm1.IdHTTPServerCreatePostStream(AContext: TIdContext;
  AHeaders: TIdHeaderList; var VPostStream: TStream);
begin
 //VPostStream:=TFileStream.Create('c:\1111111',fmCreate);
//会包含所有信息,不仅仅上传的文件,还有http 协议信息
  VPostStream := TMemoryStream.Create;
end;

procedure TForm1.IdHTTPServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  LocalDoc: string;
  ByteSent: Cardinal;
  ResultFile: TFileStream;
  memoryStream: TMemoryStream;
  contentType: string;
  s: String;
  Decoder, NewDecoder: TIdMessageDecoder;
  DestStream: TStream;
  IdPostStream, IdDestStream: TStream; //TIdStreamVcl ;
  MsgEnd: Boolean;
  Stream: TMemoryStream;
  procedure DecodeFormData(const Header: string; ASourceStream:
    TStream);
  var
    MsgEnd: Boolean;
    Decoder: TIdMessageDecoder;
    Tmp: string;
    Dest: TMemoryStream;
  begin
    MsgEnd := False;
    Decoder := TIdMessageDecoderMIME.Create(nil);
    try
      Decoder.SourceStream := ASourceStream;
      Decoder.FreeSourceStream := False;
      TIdMessageDecoderMIME(Decoder).MIMEBoundary := Decoder.ReadLn;
      //Decoder.ReadLn;
      repeat
        Decoder.ReadHeader;
        {case Decoder.PartType of
          mcptUnknown:
          raise Exception('Unknown form data detected');
          mcptText:
            begin
              Tmp :=  Decoder.Headers.Values['Content-Type'];
              Dest := TMemoryStream.Create;
              try
                Decoder := Decoder.ReadBody(Dest, MsgEnd);
                if AnsiSameText(Fetch(Tmp, ';'), 'multipart/mixed') then
                  DecodeFormData(Tmp, Dest)
                else
                  // use Dest as needed...
              finally
                FreeAndNil(Dest);
              end;
            end;
          mcptAttachment: }
            begin
              Tmp := ExtractFileName(Decoder.FileName);
              if Tmp <> '' then
                Tmp := ExtractFilePath(Application.ExeName) + 'web\upload\'+Tmp
              else
                Tmp := MakeTempFilename('c:\temp\');
              Dest := TMemoryStream.Create;//TFileStream.Create(Tmp, fmCreate);
              try
                NewDecoder := Decoder.ReadBody(Dest, MsgEnd);
                ///////yu add begin
                if  NewDecoder <>nil then
                begin
                NewDecoder.SourceStream := ARequestInfo.PostStream;   //yu
                NewDecoder.FreeSourceStream := False; //yu
                TIdMessageDecoderMIME(NewDecoder).MIMEBoundary  :=  TIdMessageDecoderMIME(Decoder).MIMEBoundary ;
                end;
                if (Decoder <>nil) and(Decoder.Filename<>'') then
                Dest.SaveToFile(Tmp);
                ///////////yu add  end
                Decoder.Free;
                Decoder := NewDecoder;

              finally
                FreeAndNil(Dest);
              end;
            end;
        //end;
      until (Decoder = nil) or MsgEnd;
    finally
      FreeAndNil(Decoder);
    end;
  end;
begin
  LocalDoc := ExpandFileName(Edit1.Text + ARequestInfo.Document);
  if LocalDoc[Length(LocalDoc)] = '\' then
    Delete(LocalDoc, Length(LocalDoc), 1);

  if not FileExists(LocalDoc) and DirectoryExists(LocalDoc) then
    if FileExists(ExpandFileName(LocalDoc + '/index.html')) then
      LocalDoc := ExpandFileName(LocalDoc + '/index.html')
    else if FileExists(ExpandFileName(LocalDoc + '/index.htm')) then
      LocalDoc := ExpandFileName(LocalDoc + '/index.htm');


  S := ARequestInfo.ContentType;
  if AnsiSameText(Fetch(S, ';'), 'multipart/form-data') then
  begin
    DecodeFormData(S, ARequestInfo.PostStream)  ;

  end
  else
    // use request data as needed...

  if FileExists(LocalDoc) then
  begin
    if AnsiSameText(Copy(LocalDoc, 1, Length(edit1.text)), Edit1.Text) then
    begin
      ResultFile := TFileStream.create(LocalDoc, fmOpenRead or
        fmShareDenyWrite);
      try
        AResponseInfo.ResponseNo := 200;

        contentType := GetMimeTypeFromFile(LocalDoc);
        if LeftStr(ContentType, 4) = 'text' then
        begin
          ContentType := ContentType + '; charset=gb2312';
        end;

        AResponseInfo.ContentType := contentType;
        AResponseInfo.ContentLength := ResultFile.Size;
        AResponseInfo.ContentStream := ResultFile;
      except
        ResultFile.Free;
        // We   must   free   this   file   since   it   won 't   be   done   by   the   web   server   component
      end;
      //下载文件
      //ByteSent := AResponseInfo.ServeFile(AContext, LocalDoc);
    end;
  end
  else
  begin
    AResponseInfo.ResponseNo := 404;
    AResponseInfo.ContentType := 'text/plain' + '; charset=gb2312';
    //乱码须用流的形式
    {memoryStream:=TMemoryStream.Create;
    s:='找不到' + ARequestInfo.Document;
    memorystream.write(PAnsichar(s)^,length(s));
    AResponseInfo.ContentStream := memorystream; }
    AResponseInfo.ContentText :=
      '<html>' + #13#10 +
      '<body>' + #13#10 +
      'Page not found:<br>' + #13#10 +
      '<b>' + ARequestInfo.Document + '</b>' + #13#10 +
      '</body>' + #13#10 +
      '</html>';

  end;
  Memo1.Lines.Add(AReQuestInfo.Document);
end;


TIdMessageDecoderMIME.ReadBody
跟踪发现
//不大明白为啥要多加'--'
    if MIMEBoundary <> '' then begin
      BoundaryStart :=  '--' + MIMEBoundary; {Do not Localize}
      BoundaryEnd := BoundaryStart + '--'; {Do not Localize}
    end;

实际上传文件测试发现,发送的数据流中 没有多加的'--'.多此一举??

if IsBinaryContentTransferEncoding then
        begin
          //For binary, need EOL because the default LF causes spurious CRs in the output...
          LLine := ReadLnRFC(VMsgEnd, EOL, '.', Indy8BitEncoding); //do not localize
        end

上传rar文件测试,发现rar文件中的单个的#10, #13字符, 全部被替换成了#13#10两个字符,
结果文件变大了,rar文件也无法打开.
明明已经说了IsBinaryContentTransferEncoding, 还要多此一举.
搞了一天,上传也没搞好.

要不自己处理post收到的数据,不用
Decoder := Decoder.ReadBody(Dest, MsgEnd);


idhhtp 阻塞式.可设置为非阻塞式

ICS非阻塞式

使用ICS V8 Gold.
编译 WebDemos下的OverbyteIcsWebServ
启动OverbyteIcsWebServ.exe
访问http://localhost/formupload.html  上传正常.














    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多