...

Source file src/github.com/go-ldap/ldap/v3/response.go

Documentation: github.com/go-ldap/ldap/v3

     1  package ldap
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  
     8  	ber "github.com/go-asn1-ber/asn1-ber"
     9  )
    10  
    11  // Response defines an interface to get data from an LDAP server
    12  type Response interface {
    13  	Entry() *Entry
    14  	Referral() string
    15  	Controls() []Control
    16  	Err() error
    17  	Next() bool
    18  }
    19  
    20  type searchResponse struct {
    21  	conn *Conn
    22  	ch   chan *SearchSingleResult
    23  
    24  	entry    *Entry
    25  	referral string
    26  	controls []Control
    27  	err      error
    28  }
    29  
    30  // Entry returns an entry from the given search request
    31  func (r *searchResponse) Entry() *Entry {
    32  	return r.entry
    33  }
    34  
    35  // Referral returns a referral from the given search request
    36  func (r *searchResponse) Referral() string {
    37  	return r.referral
    38  }
    39  
    40  // Controls returns controls from the given search request
    41  func (r *searchResponse) Controls() []Control {
    42  	return r.controls
    43  }
    44  
    45  // Err returns an error when the given search request was failed
    46  func (r *searchResponse) Err() error {
    47  	return r.err
    48  }
    49  
    50  // Next returns whether next data exist or not
    51  func (r *searchResponse) Next() bool {
    52  	res, ok := <-r.ch
    53  	if !ok {
    54  		return false
    55  	}
    56  	if res == nil {
    57  		return false
    58  	}
    59  	r.err = res.Error
    60  	if r.err != nil {
    61  		return false
    62  	}
    63  	r.entry = res.Entry
    64  	r.referral = res.Referral
    65  	r.controls = res.Controls
    66  	return true
    67  }
    68  
    69  func (r *searchResponse) start(ctx context.Context, searchRequest *SearchRequest) {
    70  	go func() {
    71  		defer func() {
    72  			close(r.ch)
    73  			if err := recover(); err != nil {
    74  				r.conn.err = fmt.Errorf("ldap: recovered panic in searchResponse: %v", err)
    75  			}
    76  		}()
    77  
    78  		if r.conn.IsClosing() {
    79  			return
    80  		}
    81  
    82  		packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
    83  		packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, r.conn.nextMessageID(), "MessageID"))
    84  		// encode search request
    85  		err := searchRequest.appendTo(packet)
    86  		if err != nil {
    87  			r.ch <- &SearchSingleResult{Error: err}
    88  			return
    89  		}
    90  		r.conn.Debug.PrintPacket(packet)
    91  
    92  		msgCtx, err := r.conn.sendMessage(packet)
    93  		if err != nil {
    94  			r.ch <- &SearchSingleResult{Error: err}
    95  			return
    96  		}
    97  		defer r.conn.finishMessage(msgCtx)
    98  
    99  		foundSearchSingleResultDone := false
   100  		for !foundSearchSingleResultDone {
   101  			select {
   102  			case <-ctx.Done():
   103  				r.conn.Debug.Printf("%d: %s", msgCtx.id, ctx.Err().Error())
   104  				return
   105  			default:
   106  				r.conn.Debug.Printf("%d: waiting for response", msgCtx.id)
   107  				packetResponse, ok := <-msgCtx.responses
   108  				if !ok {
   109  					err := NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
   110  					r.ch <- &SearchSingleResult{Error: err}
   111  					return
   112  				}
   113  				packet, err = packetResponse.ReadPacket()
   114  				r.conn.Debug.Printf("%d: got response %p", msgCtx.id, packet)
   115  				if err != nil {
   116  					r.ch <- &SearchSingleResult{Error: err}
   117  					return
   118  				}
   119  
   120  				if r.conn.Debug {
   121  					if err := addLDAPDescriptions(packet); err != nil {
   122  						r.ch <- &SearchSingleResult{Error: err}
   123  						return
   124  					}
   125  					ber.PrintPacket(packet)
   126  				}
   127  
   128  				switch packet.Children[1].Tag {
   129  				case ApplicationSearchResultEntry:
   130  					result := &SearchSingleResult{
   131  						Entry: &Entry{
   132  							DN:         packet.Children[1].Children[0].Value.(string),
   133  							Attributes: unpackAttributes(packet.Children[1].Children[1].Children),
   134  						},
   135  					}
   136  					if len(packet.Children) != 3 {
   137  						r.ch <- result
   138  						continue
   139  					}
   140  					decoded, err := DecodeControl(packet.Children[2].Children[0])
   141  					if err != nil {
   142  						werr := fmt.Errorf("failed to decode search result entry: %w", err)
   143  						result.Error = werr
   144  						r.ch <- result
   145  						return
   146  					}
   147  					result.Controls = append(result.Controls, decoded)
   148  					r.ch <- result
   149  
   150  				case ApplicationSearchResultDone:
   151  					if err := GetLDAPError(packet); err != nil {
   152  						r.ch <- &SearchSingleResult{Error: err}
   153  						return
   154  					}
   155  					if len(packet.Children) == 3 {
   156  						result := &SearchSingleResult{}
   157  						for _, child := range packet.Children[2].Children {
   158  							decodedChild, err := DecodeControl(child)
   159  							if err != nil {
   160  								werr := fmt.Errorf("failed to decode child control: %w", err)
   161  								r.ch <- &SearchSingleResult{Error: werr}
   162  								return
   163  							}
   164  							result.Controls = append(result.Controls, decodedChild)
   165  						}
   166  						r.ch <- result
   167  					}
   168  					foundSearchSingleResultDone = true
   169  
   170  				case ApplicationSearchResultReference:
   171  					ref := packet.Children[1].Children[0].Value.(string)
   172  					r.ch <- &SearchSingleResult{Referral: ref}
   173  
   174  				case ApplicationIntermediateResponse:
   175  					decoded, err := DecodeControl(packet.Children[1])
   176  					if err != nil {
   177  						werr := fmt.Errorf("failed to decode intermediate response: %w", err)
   178  						r.ch <- &SearchSingleResult{Error: werr}
   179  						return
   180  					}
   181  					result := &SearchSingleResult{}
   182  					result.Controls = append(result.Controls, decoded)
   183  					r.ch <- result
   184  
   185  				default:
   186  					err := fmt.Errorf("unknown tag: %d", packet.Children[1].Tag)
   187  					r.ch <- &SearchSingleResult{Error: err}
   188  					return
   189  				}
   190  			}
   191  		}
   192  		r.conn.Debug.Printf("%d: returning", msgCtx.id)
   193  	}()
   194  }
   195  
   196  func newSearchResponse(conn *Conn, bufferSize int) *searchResponse {
   197  	var ch chan *SearchSingleResult
   198  	if bufferSize > 0 {
   199  		ch = make(chan *SearchSingleResult, bufferSize)
   200  	} else {
   201  		ch = make(chan *SearchSingleResult)
   202  	}
   203  	return &searchResponse{
   204  		conn: conn,
   205  		ch:   ch,
   206  	}
   207  }
   208  

View as plain text